安安静静学JAVA(十六)

单例模式

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象

单例设计模式的作用:

  • 目的: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
  • 解决的问题: 一个全局使用的类频繁地创建与销毁。
  • 什么时候使用: 当您想控制实例数目,节省系统资源的时候。

饥汉式

    1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
  1. 在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。

  2. 定义一个静态方法返回这个唯一对象。

/**
 *
 * 单例设计模式 --- 饿汉式
 *
 *  能够在多线程环境下保证单例!   ->  实际开发可以使用
 *
 *  缺点: 不符合懒加载的原则
 */
public class Singleton {
    // 1. 私有构造方法, 不让别人创建对象
    private Singleton() {
    }

    // 2. 单例的类中创建对象
    // private
    // static:
    //  1. getInstance方法使用
    //  2. static随着类的加载而加载, 使用类加载器的特点, 保证这个对象只创建一次!!!
    // final: 防止本类修改
    private static final Singleton instance = new Singleton();

    // 3. 对外提供用于获取对象的方法
    // static : 别的类可以直接使用
    public static Singleton getInstance() {
        return instance;
    }
}
public class MyTest {
    public static void main(String[] args) {
        // 创建Singleton对象, 让Singleton是单例
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    Singleton s = Singleton.getInstance();
                    System.out.println(s);
                }
            }
        };

        for (int i = 0; i < 100; i++) {
            new Thread(r).start();
        }

    }
}

懒汉式

  • 懒汉单例设计模式就是调用getInstance()方法时实例才被创建,先不急着实例化出对象,等要用的时候才例化出对象。

普通实现

/**
 * 单例设计模式 --- 懒汉式
 *
 *  保证了懒加载的原则
 *
 *  缺点: 多线程环境下不能保证单例
 *
 *  实际开发过程中, 不能用!!!
 *
 */
public class Singleton {

    // 1. 私有构造方法
    private Singleton() {
    }

    // 2. 只做声明Singleton, 不创建
    private static Singleton instance; // 默认值是null

    // 3. 对外提供用于获取对象的方法
    public static Singleton getInstance()  {
        // 只有第一次执行getInstance方法的时候需要创建对象,
        // 后面再执行getInstance方法, 直接返回第一次创建的对象
        if (instance == null) {
            // 对象的创建
            instance = new Singleton();
        }
        // 代码执行到这里, 说明instance一定不为null  -> 直接返回
        return instance;
    }

}
public class MyTest {
    public static void main(String[] args) {
        // 创建Singleton对象, 让Singleton是单例
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    Singleton s = Singleton.getInstance();
                    System.out.println(s);
                }
            }
        };

         for (int i = 0; i < 100; i++) {
            new Thread(r).start();
         }

    }
}

同步方法实现

/**
 *
 *  单例设计模式  --- 懒汉式(同步方法)
 *
 *  懒加载, 多线程环境下没有问题   ->   实际开发可以使用!!!
 *
 *  缺点: 每次执行都要获取锁和释放锁! 浪费资源!
 *
 */
public class Singleton {
    // 1. 私有构造方法
    private Singleton() {
    }

    // 2. 只做声明Singleton, 不创建
    private static Singleton instance; // 默认值是null

    // 3. 对外提供用于获取对象的方法(同步方法)
    public synchronized static Singleton getInstance()  {
        // 只有第一次执行getInstance方法的时候需要创建对象,
        // 后面再执行getInstance方法, 直接返回第一次创建的对象
        if (instance == null) {
            // 对象的创建
            instance = new Singleton();
        }
        // 代码执行到这里, 说明instance一定不为null  -> 直接返回
        return instance;
    }
}
public class MyTest {
    public static void main(String[] args) {
        // 创建Singleton对象, 让Singleton是单例
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    Singleton s = Singleton.getInstance();
                    System.out.println(s);
                }
            }
        };

         for (int i = 0; i < 100; i++) {
            new Thread(r).start();
         }

    }
}

使用同步锁

public class Singleton {
    // 1. 私有构造方法
    private Singleton() {
    }

    // 2. 只做声明Singleton, 不创建
    private static Singleton instance; // 默认值是null


    /*
        如果这个方法写成同步方法, 无论什么时候, 执行getInstance方法都会获取锁和释放锁
        我们希望, 先不着急获取锁, 等会再获取

        现在的格式起到的效果:  在单线程的情况下, 保证只有第一次执行的时候, 获取锁创建对象
        而后面的每一次执行都不会获取锁和创建对象
     */
    // 3. 对外提供用于获取对象的方法(同步方法)
    public static Singleton getInstance()  {
        // 只有第一次执行getInstance方法的时候需要创建对象,
        // 后面再执行getInstance方法, 直接返回第一次创建的对象
        if (instance == null) {

            synchronized (Singleton.class) {
                // 对象的创建
                instance = new Singleton();
            }
        }
        // 代码执行到这里, 说明instance一定不为null  -> 直接返回
        return instance;
    }
}
public class MyTest {
    public static void main(String[] args) {
        // 创建Singleton对象, 让Singleton是单例
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    Singleton s = Singleton.getInstance();
                    System.out.println(s);
                }
            }
        };

         for (int i = 0; i < 100; i++) {
            new Thread(r).start();
         }

    }
}

双重检查

/**
 * 单例设计模式 --- 双重检查
 *
 * 优点 : 懒加载,  多线程保证只有一个对象,  不会每一次都获取锁和释放锁
 */
public class Singleton {
    // 1. 私有构造
    private Singleton() {
    }
    // 2. 声明引用, 不创建对象
    // volatile : 禁止指令重排序
    private static volatile Singleton instance;
    // 3. 对外提供用于获取对象的方法
    public static Singleton getInstance() {
        // 判断
        if (instance == null) { // 和下面的同步-> 减少获取锁的次数
            synchronized (Singleton.class) {
                if (instance == null) { // 保证单例!!!
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
public class MyTest {
    public static void main(String[] args) {
        // 创建Singleton对象, 让Singleton是单例
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    Singleton s = Singleton.getInstance();
                    System.out.println(s);
                }
            }
        };

         for (int i = 0; i < 100; i++) {
            new Thread(r).start();
         }

    }
}

多例模式

多例模式,是一种常用的软件设计模式。通过多例模式可以保证系统中,应用该模式的类有固定数量的实例。

实现步骤:

1.创建一个类, 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。

​2.在类中定义该类被创建的总数量

​3.在类中定义存放类实例的list集合

​4.在类中提供静态代码块,在静态代码块中创建类的实例

​5.提供获取类实例的静态方法

/*
    多例设计模式

        创建对象的时候, 只能创建固定个数个实例
 */
public class Multition {

    // 1. 私有构造
    private Multition() {
    }

    // 2. 创建变量 , 用来代表集合中对象的个数
    private static int count = 3;

    // 3. 创建集合
    private static ArrayList<Multition> list = new ArrayList<>();

    // 在静态代码块中, 创建n个对象, 放到集合中
    // 类加载的时候就执行, 只执行一次
    static {
        for (int i = 0; i < count; i++) {
            list.add(new Multition());
        }
    }

    // 对外提供用来获取对象的方法
    public static Multition getInstance() {
        // 创建随机数对象
        Random r = new Random();
        // 获取随机数(集合中的随机索引)
        int randomIndex = r.nextInt(list.size());
        // 获取这个索引对应的对象
        Multition instance = list.get(randomIndex);
        // 返回集合中的一个元素
        return instance;
    }
}
public class MyTest {
    public static void main(String[] args) {

        for (int i = 0; i < 100; i++) {
            Multition m = Multition.getInstance();
            System.out.println(m);
        }

    }
}

枚举

不使用枚举存在的问题:可以给性别传入任意的字符串,导致性别是非法的数据,不安全。

枚举的作用:

一个方法接收的参数是固定范围之内的时候,那么即可使用枚举。

枚举的概念:

枚举是一种特殊类。枚举是有固定实例个数的类型,我们可以把枚举理解成有固定个数实例的多例模式。

定义枚举的格式

在这里插入图片描述

枚举的本质是一个类,所以枚举中还可以有成员变量,成员方法等在这里插入图片描述

在这里插入图片描述配合 swich 用法

// RED, YELLOW, GREEN
// 都是Light类的对象,
// 默认修饰符: public static final
public enum Light {
    RED, YELLOW, GREEN;
}
public class Demo01 {
    public static void main(String[] args) {

        // 指定灯是什么颜色
        Light l = Light.GREEN;

        switch (l) {
            case GREEN:
                System.out.println("绿灯行!~");
                break;
            case YELLOW:
                System.out.println("黄灯等!~");
                break;
            case RED:
                System.out.println("红灯停!~");
                break;
        }

    }
}

用枚举对成员变量, 进行描述


public enum Season {
    // 这几个都是Season类的对象
    SPRING("春天在哪里"), SUMMER("夏天悄悄过去"), AUTUMN("秋天不回来"), WINTER("冬天里的一把火");

    // 成员变量, 进行描述
    private String describe;

    // 构造方法给成员变量赋值
    Season(String describe) {
        this.describe = describe;
    }

    public String getDescribe() {
        return describe;
    }
}
public class Demo02 {
    public static void main(String[] args) {

        Season s = Season.AUTUMN;
        System.out.println(s.getDescribe());

    }
}

枚举实现单例模式

 /**
 * 枚举实现单例设计模式
 */
public enum Singleton {
    INSTANCE;
}
public class MyTest {
    public static void main(String[] args) {
        // 创建Singleton对象, 让Singleton是单例
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    Singleton s = Singleton.INSTANCE;
                    System.out.println(s.hashCode());
                }
            }
        };

         for (int i = 0; i < 100; i++) {
            new Thread(r).start();
         }

    }
}

枚举实现单例模式

  • 它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。

普通工厂模式

工厂模式其实就是用来帮我们创建对象的

工厂模式的作用:

定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。可以解决类与类之间耦合的问题.

注意:

作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

代码:

public class BenZ implements Car {
    @Override
    public void run() {
        System.out.println("买了一辆奔驰, 跑的太慢!!!");
    }
}
public class BMW implements Car {
    @Override
    public void run() {
        System.out.println("买了一辆宝马, 操作还可以!");
    }
}
public class Ferrari implements Car {
    @Override
    public void run() {
        System.out.println("买了一辆法拉利, 跑的贼快!!~");
    }
}
public class Porsche implements Car {
    @Override
    public void run() {
        System.out.println("买了一辆破二手车, 太贵!!!");
    }
}

public interface Car {
    void run();
}

public class CarFactory {

    // 对外提供用来创建对象的方法
    public Car createInstance(String brand) {
        if ("benz".equalsIgnoreCase(brand)) {
            return new BenZ();
        } else if ("bmw".equalsIgnoreCase(brand)){
            return new BMW();
        } else if ("porsche".equalsIgnoreCase(brand)){
            return new Porsche();
        } else if ("ferrari".equalsIgnoreCase(brand)){
            return new Ferrari();
        } else {
            return null;
        }
    }

}

public class MyTest {
    public static void main(String[] args) {
        // 创建工厂的对象
        CarFactory factory = new CarFactory();
        // 使用工厂提供的方法, 创建Car的对象
        BenZ benz = (BenZ) factory.createInstance("benz");
        benz.run();
        BMW bmw = (BMW) factory.createInstance("bmw");
        bmw.run();
        Car porsche = factory.createInstance("porsche");
        porsche.run();
        Car ferrari = factory.createInstance("ferrari");
        ferrari.run();
    }
}

方法引用

是什么:是对Lambda的简化

方法引用的前提:

不是所有的匿名内部类都可以改成Lambda

不是多有的lambda都可以改成方法引用!!!

Lambda表达式中的内容, 是已经定义好的.

-

格式:

在这里插入图片描述

适配器模式

public interface Monk {

    void seat();

    void speak();

    void eatVegetable();

    void dragTree();

    void eatMeat();

}

public abstract class MonkAdapter implements Monk {
    @Override
    public void seat() {
    }

    @Override
    public void speak() {
    }

    @Override
    public void eatVegetable() {
    }

    @Override
    public void dragTree() {
    }

    @Override
    public void eatMeat() {
    }
}
public class FlowerMonk extends MonkAdapter {

    @Override
    public void dragTree() {
        System.out.println("倒拔垂杨柳");
    }

    @Override
    public void eatMeat() {
        System.out.println("大口吃肉!~");
    }
}

public class OneRest extends MonkAdapter {
    @Override
    public void seat() {
        System.out.println("打坐");
    }

    @Override
    public void speak() {
        System.out.println("格级格级");
    }

    @Override
    public void eatVegetable() {
        System.out.println("吃素");
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值