返回顶部

设计模式 (1): 5 种创建型模式 (结合代码详解)

这个是我学习 23 种设计模式的第 1 篇,代码和文章都是自己的理解和编写的~



引言:没模式,怎么生产对象?

  • 全局变量:全局共享的对象、全局访问点
  • New 对象:构造私有的对象
  • 属性装配:setter方法
  • 复制对象:增加具体对象的数量

直接生产的问题

对于 全局变量:

  • 拓展性低
  • 不能延时初始化
  • 没有封装:
    • 对外暴露自己,可能被 误改 或 恶意攻击
    • 作用域不受限,随意访问(单例模式需要 先引用单例类)

对于 New 对象:

  • 没有可拓展性,即便封装成函数,也只是提高复用性
  • 复杂的属性配置,复杂对象很麻烦
  • 随着具体种类的增加,种类变得难以维护

对于属性装配:

  • setter方法逐个注入太臃肿,难以维护

对于复制对象:

  • 通过构造器、setter/getter 复制对象的效率低,属性多 还容易出错

设计模式,解决痛点

  • 单例模式 解决 全局变量 的问题
  • 工厂模式/抽象工厂 解决 New 对象(族) 的问题
  • 建造者模式 解决 属性装配 的问题
  • 原型模式 解决 复制对象 的问题

1 单例模式

需考虑的问题:

  • 是否线程安全
  • 是否延迟创建
  • 有无破坏单例的方法

饿汉单例

public class _01Eager {
    // 不延迟单例
    // 类初始化时创建单例
    private static final _01Eager instance = new _01Eager();
    private _01Eager(){}
    public static _01Eager getInstance(){
        return instance;
    }
}

懒汉单例

public class _02Lazyer {
    // 方法延迟单例
    // 相比于 饿汉式,把 instance 的创建
    // 从 类初始化时 移动到 方法调用时
    private static _02Lazyer instance;
    private _02Lazyer(){}
    public static synchronized _02Lazyer getInstance(){
        if(instance == null)
            instance = new _02Lazyer();
        return instance;
    }
}

双重检验单例

public class _03DoubleCheck {
    // 方法延迟单例
    // 相比 懒汉式,缩小锁粒度
    private static _03DoubleCheck instance;
    private _03DoubleCheck(){}
    public static _03DoubleCheck getInstance(){
        if(instance == null){
            synchronized (_03DoubleCheck.class){
                if(instance == null) {
                    instance = new _03DoubleCheck();
                }
            }
        }
        return instance;
    }
}

静态内部类单例

public class _04Static implements Serializable {
    private static class Static {
        private final static _04Static instance = new _04Static();
    }
    private _04Static(){}
    public static _04Static getInstance(){
        return Static.instance;
    }
}

破坏单例 (反射、反序列化)

(导入序列化工具依赖:org.apache.commons.commons-lang3

public class StaticAttack {
    StaticAttack(){}
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 测试 反射和反序列化 破坏 静态内部类
        staticAttack();
    }
    public static void staticAttack() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 单例对象
        _04Static obj = _04Static.getInstance();
        isSingleton(obj, _04Static.getInstance()); // true
        // 测试是否可以破坏单例
        _04Static newObj1, newObj2;
        // 反射创建 新对象 可以破坏单例
        Constructor<_04Static> constructor = _04Static.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        newObj1 = constructor.newInstance();
        isSingleton(obj, newObj1); // false
        // 反序列化创建 新对象 可以破坏单例
        byte[] serialize = SerializationUtils.serialize(obj);
        newObj2 = SerializationUtils.deserialize(serialize);
        isSingleton(obj, newObj2); // false
    }
    public static void isSingleton(Object obj1, Object obj2){
        System.out.println("是否是单例? " + (obj1 == obj2));
    }
}

枚举类单例

// 枚举类可以避免 反射 和 反序列化 破坏单例
public enum _05Enum {
    SINGLETON;
    // 单例的方法
    public String doSomething(){
        return "处理结束";
    }
}
// 调用单例的方法
_05Enum.SINGLETON.doSomething();

2 工厂模式

简单工厂模式

  • 消费者:依赖 商店
  • 商店:依赖 工厂,返回 具体产品
  • 工厂:if - else 地创建 具体产品
  • 产品:产品种类 通过 实现 很多抽象产品(接口)
public class sf {
    // 抽象产品类 Vehicle
    interface Vehicle {}
    // Vehicle 的 具体产品
    static class Car implements Vehicle {
        public String toString() {
            return "Car";
        }
    }
    static class Bike implements Vehicle {
        public String toString() {
            return "Bike";
        }
    }
    // 所有具体产品 都共用 抽象产品的工厂
    static class VehicleFactory {
        Vehicle createVehicle(String type){
            if(type == null)
                return null;
            Vehicle vehicle = null;
            if(type.equalsIgnoreCase("Car"))
                vehicle = new Car();
            else if(type.equalsIgnoreCase("Bike"))
                vehicle = new Bike();
            return vehicle;
        }
    }
}

工厂方法模式

public class fm {
    // 抽象产品类 Vehicle
    interface Vehicle {}
    // Vehicle 的 具体产品
    static class Car implements Vehicle {
        public String toString() {
            return "Car";
        }
    }
    static class Bike implements Vehicle {
        public String toString() {
            return "Bike";
        }
    }
    // Vehicle 的 抽象工厂
    static abstract class VehicleFactory {
        abstract Vehicle createVehicle();
    }
    // *继承* 抽象工厂
    // 一个具体产品 对应 一个具体工厂
    static class CarFactory extends VehicleFactory {
        Vehicle createVehicle(){
            return new Car();
        }
    }
    static class BikeFactory extends VehicleFactory {
        Vehicle createVehicle() {
            return new Bike();
        }
    }
}

3 抽象工厂模式

代码实现

public class af {
    // 抽象工厂用于产品族
    // 产品族 和 各自的抽象工厂
    interface Vehicle {}
    interface Accessory {}
    // interface Engine {} 产品族拓展的例子
    interface VehicleFactory {
        Vehicle createVehicle();
    }
    interface AccessoryFactory {
        Accessory createAccessory();
    }
    // interface EngineFactory { Engine createEngine();}

    // Vehicle 的 具体产品
    static class Car implements Vehicle {
        public String toString() {
            return "Car";
        }
    }
    static class Bike implements Vehicle {
        public String toString() {
            return "Bike";
        }
    }
    // Accessory 的具体产品
    static class CarAccessory implements Accessory {
        public String toString() {
            return "CarAccessory";
        }
    }
    static class BikeAccessory implements Accessory {
        public String toString() {
            return "BikeAccessory";
        }
    }
    // 每 *实现* 一个接口,产品族就拓展一类产品
    // 产品族工厂 实现了 多个接口,实现产品族的可拓展性
    static class CarFactory implements
            VehicleFactory, AccessoryFactory //,EngineFactory
    {
        public Vehicle createVehicle() {
            return new Car();
        }
        public Accessory createAccessory() {
            return new CarAccessory();
        }
    }
    static class BikeFactory implements
            VehicleFactory, AccessoryFactory //,EngineFactory
    {
        public Vehicle createVehicle() {
            return new Bike();
        }
        public Accessory createAccessory() {
            return new BikeAccessory();
        }
    }
}

对比三种工厂模式

| 简单工厂模式:
- A 产品:A1 - A2
	 简单工厂
	/ if-else \ 
  A1           A2 

| 工厂方法模式:
- A 产品:A1 - A2
      A 抽象工厂(抽象类)
      - 生产 A
     /  继承   \
 A1 具体工厂   A2 具体工厂
 - 生产 A1     - 生产 A2

| 抽象工厂模式:
- (A, B, ...) 产品* 族 *:A1 - A2 | B1 - B2 | C ..
 A 抽象工厂(接口)   B 抽象工厂(接口)   C 抽象工厂
 - 生产 A (接口)    - 生产 B (接口)
        \     多实现     /
      (A1, B1) 具体产品族工厂
	   - 生产 A1 (实现接口)
	   - 生产 B1 (实现接口)

可以看到,抽象工厂可以实现最复杂的功能,但是在简单情形下增加了复杂性

如何选择工厂方法和抽象工厂?

在实际应用中,需要根据具体的需求和场景选择合适的模式:

  • 如果产品种类较少,可以使用工厂方法模式
  • 如果产品种类较多,形成了产品族(并且 产品族 有可能 增删 产品),可以使用抽象工厂模式

4 建造者模式

可定制的建造者模式

public class Build2 {
    @Data
    @ToString
    public static class Car {
        private String name;
        private String accessory;
        private String engine;
    }
    public static class CarBuilder {
        private Car car = new Car();
        public CarBuilder appendName(String name) {
            car.setName(name);
            return this;
        }
        public CarBuilder appendAccessory(String acc) {
            car.setAccessory(acc);
            return this;
        }
        public CarBuilder appendEngine(String eng) {
            car.setEngine(eng);
            return this;
        }
        public Car build() {
            Car Car = car;
            // 构建完成之后初始化 car
            car = new Car();
            return Car;
        }
    }
}

不可定制的建造者 "工厂" 模式

public class Build {
    @Data
    @ToString
    public static class Car {
        private String name;
        private String accessory;
        private String engine;
    }
    // 私有化建造者
    private static class CarBuilder {
        private Car car = new Car();
        public CarBuilder appendName(String name) {
            car.setName(name);
            return this;
        }
        public CarBuilder appendAccessory(String acc) {
            car.setAccessory(acc);
            return this;
        }
        public CarBuilder appendEngine(String eng) {
            car.setEngine(eng);
            return this;
        }
        public Car build() {
            Car Car = car;
            // 构建完成之后初始化 car
            car = new Car();
            return Car;
        }
    }
    // 对外提供 工厂,封装 建造过程
    public static class CarFactory {
        private final CarBuilder cb = new CarBuilder();
        public Car getBWMCar(){
            return cb.appendName("BWM666")
                    .appendAccessory("尊贵奢华车身")
                    .appendEngine("行星发动机")
                    .build();
        }
        public Car getTeslaCar(){
            return cb.appendName("Tesla888")
                    .appendAccessory("自动驾驶模块")
                    .appendEngine("飞船发动机")
                    .build();
        }
    }
}

对比抽象工厂模式

看起来,抽象工厂和建造者都创建了很多内容
但是从多相关对象和单复杂对象的角度就可以发现他们的不同:

  • 抽象工厂模式可以创建一系列的产品族,而建造者模式可以定义一系列具体成员的组装

因此:

  • 抽象工厂模式更适合创建 一组相关对象,往往是多个不同类对象
  • 建造者模式更适合创建 单个复杂对象,往往是单个复杂对象或者同类对象的集合(list、map)

5 原型模式

避免使用 参数构造器、set方法 复制对象,提高 复制 对象的性能

浅拷贝原型模式

public class Prototype implements Cloneable {
    @Override
    
}

深拷贝原型模式

posted @ 2023-10-08 23:29  你好,一多  阅读(13)  评论(0编辑  收藏  举报