设计模式-创建型

写在前面

​ 发现对于落地这件事情还是要静下心一个一个目标完成,设计模式一直搁浅了好久也没个系统整理,作为网上标配开篇,最近还是补上这个作业吧

  1. 为什么用设计模式

    • 设计模式是前人总结下来的经验,对于扩展性和可维护性有很大帮助
    • 也是为了使设计变得简单,容易阅读
  2. 设计模式原则(SOLID)

    • 单一职责原则(Single Responsibility Principle):可以理解为最好一个类只负责一项职责
    • 开闭原则(Open Close Priciple):尽量对扩展开放,对修改关闭
    • 里氏替换原则(Liskov Substitution Principle):引用父类处可以用任意子类代替
    • 接口隔离原则(Interface Segregation priciple):建立单一接口,最好是一个类依赖一个接口,而不是多个类依赖一个接口
    • 依赖倒置原则 (Dependency InVersion Principle) :调用方和实现方都应该依赖抽象,彼此相互独立,实现类应该依赖抽象,而不能反过来
    • 迪米特法则(Law of Demeter):一个对象保持对其他对象最少的了解
    • 合成复用原则(Composite/Aggregate Reuse Principle):尽量使用组合/聚合,不要使用继承,继承基类会暴露实现破坏封装;基类改变,子类实现也需要改变;实现是静态的,不够灵活
  3. 如何使用设计模式

    以上原则只是设计参考的一个约束,并不绝对,对于“最好的设计模式就是不用设计模式”,我们还没有达到这个境界,只有合适的场景用更合适的方法。

设计模式-创建型

目的:实例化过程的解耦

​ 我们原先想获取一个新对象

1
Object o = new Object();

之后在创建新对象的场景可以参考考虑一下使用以下的思路

  1. 单例模式
    说明:一个类只能有一个实例,提供全局唯一的访问点
    • 匿名内部类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      class SingletonInnerClass {
      // 私有构造器保证不能new 创建新实例
      private SingletonInnerClass() {
      }

      public static SingletonInnerClass getInstance() {
      return SingletonInner.instance;
      }

      private static class SingletonInner {
      private static final SingletonInnerClass instance = new SingletonInnerClass();
      }
      }
    • 枚举类型

      1
      2
      3
      enum SingletonEnum {
      INSTACN;
      }
    • 双重检查锁

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      class SingletonDCL {
      private volatile static SingletonDCL instance;

      private SingletonDCL() {

      }

      public static SingletonDCL getInstance() {
      if (instance == null) {
      synchronized (SingletonDCL.class) {
      if (instance == null) {
      instance = new SingletonDCL();
      }
      }
      }
      return instance;
      }
      }
    • Spring单例注册表

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      /** Cache of singleton objects: bean name to bean instance. */
      private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
      /** Cache of singleton factories: bean name to ObjectFactory. */
      private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
      /** Cache of early singleton objects: bean name to bean instance.
      提前曝光的单例Cache
      */
      private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

      @Nullable
      protected Object getSingleton(String beanName, boolean allowEarlyReference) {
      // 一级缓存 获取单例的bean
      Object singletonObject = this.singletonObjects.get(beanName);
      // 判断bean是否在创建中(并未创建完)
      if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
      // 二级缓存 获取提前曝光的单例
      singletonObject = this.earlySingletonObjects.get(beanName);
      // 判断是否允许提前引用
      if (singletonObject == null && allowEarlyReference) {
      // 三级缓存 获取单例bean
      ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
      if (singletonFactory != null) {
      // 放入二级缓存 并删除三级缓存中的bean
      singletonObject = singletonFactory.getObject();
      this.earlySingletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
      }
      }
      }
      }
      return singletonObject;
      }

      上面也直接说了spring 对于循环依赖的解决方案

  2. 简单工厂

    说明:根据传入的变量决定输出什么样的实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    interface Product {
    void use();
    }
    // 产品实现
    class ProductA implements Product {
    @Override
    public void use() {
    System.out.println("product A");
    }
    }

    class ProductB implements Product {

    @Override
    public void use() {
    System.out.println("product B");
    }
    }
    // 工厂
    class Factory {
    public Product produce(String type) {
    if ("A".equals(type)) {
    return new ProductA();
    } else if ("B".equals(type)) {
    return new ProductB();
    } else {
    return null;
    }
    }
    }
  1. 工厂方法

    说明:创建对象行为进行抽象,在子类里实现逻辑

    适用场景:

    • 如下是spring中的工厂方法接口

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      public interface FactoryBean<T> {
      @Nullable
      T getObject() throws Exception;

      @Nullable
      Class<?> getObjectType();

      default boolean isSingleton() {
      return true;
      }
      }
    • jdk中Collection类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      public interface Collection<E> extends Iterable<E> {
      ...
      // 这是一个工厂方法
      Iterator<E> iterator();
      ...
      }
      // 实现在子类中
      public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
      public Iterator<E> iterator() {
      return new Itr();
      }
      }
  1. 抽象工厂

    说明:创建相关或依赖对象的家族,而无需明确指定具体类

    - Collection类中抽象了多个工厂方法,本身又是一个抽象的创建类
    
  2. 建造者模式

    说明:封装一个对象复杂的构建过程

    • lombok @Builder

      1
      2
      3
      4
      Builder builder = Builder
      .age(10)
      .name("builder")
      .build();
  1. 原型模式

    说明:实例对象的复制获取新实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /**
    * 浅拷贝
    * 对象内的引用也被复制时为深拷贝
    */
    @Data
    @AllArgsConstructor
    class Prototype implements Cloneable {
    private String name;
    private Map<String, String> map;

    @Override
    public Prototype clone() throws CloneNotSupportedException {
    Prototype prototype = (Prototype) super.clone();
    prototype.map = map;
    prototype.name = name;
    return prototype;
    }
    }
  2. 总结

    以上是对创建型的设计模式的一些demo及一些源码的引用,目的是尽快的理解和快速的用起来,后续会补全UML图

    其中最常用的是单例模式/工厂方法/抽象工厂/建造者模式,设计模式的主要目的也是为了代码的可维护性和可扩展性,把会变动的地方和不变的地方隔离开来

如有不正确的地方欢迎大佬指正