设计模式-创建型

目的:实例化过程的解耦

写在前面

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

  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. 如何使用设计模式

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

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

Object o = new Object();

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

  1. 单例模式

    说明:一个类只能有一个实例,提供全局唯一的访问点

    应用场景:控制资源场景,例如数据库连接池,线程池等

    • 匿名内部类

      class SingletonInnerClass {
        // 私有构造器保证不能new 创建新实例
          private SingletonInnerClass() {
          }
      
          public static SingletonInnerClass getInstance() {
              return SingletonInner.instance;
          }
      
          private static class SingletonInner {
              private static final SingletonInnerClass instance = new SingletonInnerClass();
          }
      }
    • 枚举类型

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

      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单例注册表

      /** 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. 简单工厂

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

    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;
            }
        }
    }
  3. 工厂方法

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

    适用场景:

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

      public interface FactoryBean<T> {
          @Nullable
          T getObject() throws Exception;
      
          @Nullable
          Class<?> getObjectType();
      
          default boolean isSingleton() {
              return true;
          }
      }
    • jdk中Collection类

      
      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();
          }
      }
  4. 抽象工厂

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

    适用场景:对象的创建和使用隔离开来

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

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

    适用场景:crud时候,优化繁琐的实体构建过程

    • lombok @Builder

      Builder builder = Builder
                         .age(10)
                          .name("builder")
                          .build();
  6. 原型模式

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

    //浅拷贝,仅对象内的引用也被复制时为深拷贝
    @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;
        }
    }
  7. 总结

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

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

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

本文由博客群发一文多发等运营工具平台 OpenWrite 发布

Jevon
1 声望0 粉丝

show me the code