# design-pattern **Repository Path**: li_mingzhu/design-pattern ## Basic Information - **Project Name**: design-pattern - **Description**: 设计模式 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-12-13 - **Last Updated**: 2022-01-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 研磨设计模式 ### 代码组织结构: 以章节名作为包名,例如: **chapter2**表示第二章,章节包下分别有**none**包和**pattern**包,其中none包表示 不使用设计模式的解决方案,而pattern包则对应使用设计模式解决同样问题的方法。 --- ### 第二章 简单工厂模式 #### 简单工厂的定义 提供一个创建对象实例的功能,而无需关心其具体实现,被创建实例的类型可以是接口、抽象类,也可以是具体的类 #### 接口和抽象类 接口是特殊的抽象类,关于接口和抽象类的选择问题: - 优先使用接口 - 在既要定义子类的行为,又要为子类提供公共的功能时应该选择使用抽象类 #### 简单工厂模式总结 1. 简单工厂中可以创建任何对象,并不局限于创建某一个对象,不过通常工厂按指责划分只负责某个模块业务对象的创建 2. 简单工厂没必要创建实例,所以通常简单工厂中的方法都是静态方法,如果有需要甚至可以私有化构造方法 3. 工厂的功能不是用来实现业务功能,而是用来**选择合适的实现类**,所以工厂方法通常根据入参来决定如何创建对象。 --- ### 第三章 门面模式 门面模式的本质是:封装交互,简化调用 --- ### 第四章 适配器模式 #### 适配器模式中的角色 - Target 定义客户端需要的和特定领域相关的接口 - Adaptee 已经存在的接口,可以满足和客户端要求的不一致,需要被适配 - Adapter 适配器,把Adaptee适配成客户端需要的Target接口
上述提到的接口并不是java或者特定语言中的特性,而是实现了某些功能并提供对外调用的一些入口,可以是类,接口等 #### 适配器的功能 适配器的主要功能是进行功能转换,从而复用已有的代码。所以功能无需适配器来实现,适配器只是负责把不兼容的接口转换为客户端需要的样子 #### 适配器的几种实现方式 - 常见实现: 适配器为一个类,实现Target接口,在适配器的具体实现里调用Adaptee - 智能适配器: 适配器通常用来做接口兼容转换,如果适配器中有实现了新的功能,通常称为智能适配器 - 适配多个Adaptee: 即实现Target的时候,需要调用多个模块的功能。 - 缺省适配: 意思是为一个接口提供一个缺省的实现,这样就无需去实现接口,可以继承缺省实现从而有选择的覆盖需要的实现 #### 何时使用适配器 - 如果你想使用一个已经存在的类,但是它的接口不符合你的需求,可以使用适配器对其进行转换适配 - 如果你想创建一个可复用的类,这个类可能和一些不兼容的类一起工作,这种情况可以使用适配器 - 如果你想使用一些已经存在的子类,但是又不可能对每个子类适配,则可以使用适配器直接适配父类 --- ### 第五章 单例模式 单例模式是为了控制一个jvm内只存在一个实例,对于某些耗费资源的操作或者初始化需要进行耗时切繁重的任务时可以为该类配置为单例类,防止多次初始化造成的资源浪费和时间开销。 单例类的实现可以分为:懒汉模式和饿汉模式,其中饿汉模式是线程安全的,这也是一种空间换时间的典型实现。 - 饿汉模式,即声明时就直接使用new创建出对象 ```java public class Singleton { private static Singleton singleton = new Singleton(); private Singleton(){}; public static Singleton getInstance() { return singleton; } } ``` - 懒汉模式,先判定是否有实例对象再进行创建 ```java public class Singleton { private static Singleton singleton = null; private Singleton(){}; public static Singleton getInstance() { if(null == singleton) { singleton = new Singleton(); } return singleton; } } ``` #### 单例和线程安全 对于懒汉模式实现的单例,上面的代码是线程不安全的,在多线程环境下有可能产生多个实例,原因就在于null判断的代码。所以基于懒汉模式的单例实现,为了线程安全,又有如下几种实现方案 - 双重检查机制 ```java public class DoubleCheckSingleton { private static volatile DoubleCheckSingleton singleton; private DoubleCheckSingleton() {} /** * 基于双重机制的同步措施,只有在第一次创建实例时才会进行真正的同步 * 而后续的获取单例对象则无需同步,相比直接在方法上使用同步关键字的性能要更好 * @return */ public static DoubleCheckSingleton getInstance() { if(null == singleton) { synchronized (DoubleCheckSingleton.class) { if(null == singleton) { singleton = new DoubleCheckSingleton(); } } } return singleton; } } ``` - 静态内部类实现,静态内部类的实现充分利用了Java语言的特点,静态内部类作为外部类的静态成员,只有在第一次被使用的时候才会加载,这样实现了延时加载(懒汉模式),同时由jvm虚拟机保障了在静态字段上初始化数据时的线程安全。 ```java public class HolderSingleton { private HolderSingleton() {}; private static class InstanceHolder { private static HolderSingleton singleton = new HolderSingleton(); } public static HolderSingleton getInstance() { return InstanceHolder.singleton; } } ``` - 枚举实现,枚举的特殊性非常符合单例的特点,所以在《Effective Java》中也推荐最佳的单例实现方式为枚举. ```java public enum Singleton { INSTANCE; public void doSomething() { System.out.println("doSomething"); } } ``` ### 第六章 工厂方法模式 模式的定义: 定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到其子类 #### 工厂方法中的角色 - Product,定义工厂方法所创建的对象的接口,也就是实际需要使用对象的接口 - ConcreteProduct,具体的Product接口的实现对象 - Creator,创建器,声明工厂方法,工厂方法通常会返回一个Product类型的实例对象,而且多是抽象方法,也可以在Creator中提供工厂方法,让工厂方法返回一个默认的Product类型的实例 - ConcreteOperator,具体的创建器对象,覆盖Creator定义的工厂方法,返回具体的Product实例 #### 工厂方法的一般设计 - 子类在实现抽象方法时,通常不是实现所需的功能,而是在子类中做选择,选择具体的产品实现对象 - 客户端通常使用ConcreteOperator抽象类,通过创建其子类对象来实现对应的功能。 ### 第七章 抽象工厂的功能是为一系列相关对象或相互依赖的对象创建一个接口,接口内的方法是一系列相关或者相互依赖的方法。 抽象工厂通常描述的是一个产品簇,每个产品簇下又包含有多个相关的产品 抽象工厂这一角色在Java中通常的表现形式为接口,如果需要为产品簇提供共用的功能,也可以实现为抽象类 #### 抽象工厂中的角色 - AbstractFactory 抽象工厂,定义创建一系列产品对象的接口 - ConcreteFactory 具体的工厂,实现抽象工厂,具体实现一系列产品的创建 - AbstractProduct 定义一类产品对象的接口 - ConcreteProduct 具体的产品实现,通常在具体的工厂里会选择具体的产品实现对象,来创建符合抽象工厂定义的对象 - Client 客户端,主要使用抽象工厂来获取一系列所需要的产品对象,面向这些产品对象的接口编程 #### 抽象工厂的优缺点 ##### 优点 - 分离接口和实现,客户端无需知道具体的实现,做设计上的解耦 - 切换产品簇时很容易 ##### 缺点 - 不太容易扩展新产品,添加新产品时需要修改抽象工厂接口,导致所有实现都要跟着修改 - 容易造成类层次结构复杂