# DesignPattern **Repository Path**: ken010127/design-pattern ## Basic Information - **Project Name**: DesignPattern - **Description**: 设计模式 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-04-21 - **Last Updated**: 2022-03-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 设计模式 ## 原则 ### 单一功能原则 单一功能原则(Single responsibility principle)规定每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。所有它的(这个类的)服务都应该严密的和该功能平行(功能平行,意味着没有依赖)。http://blog.csdn.net/wangyang1354/article/details/51136530 ### 里氏替换原则 在面向对象的程序设计中,里氏替换原则(Liskov Substitution principle)是对子类型的特别定义。它由芭芭拉·利斯科夫(Barbara Liskov)在1987年在一次会议上名为“数据的抽象与层次”的演说中首先提出。 里氏替换原则的内容可以描述为: “派生类(子类)对象能够替换其基类(超类)对象被使用。” 以上内容并非利斯科夫的原文,而是译自罗伯特·马丁(Robert Martin)对原文的解读。其原文为: ``` Let q(x) be a property provable about objectsx of typeT. Thenq(y) should be true for objectsy of typeS whereS is a subtype ofT. ``` 芭芭拉·利斯科夫与周以真(Jeannette Wing)在1994年发表论文并提出的以上的Liskov代换原则。----维基百科 里氏替换原则我个人的理解是:在继承关系中,父类的对象如果替换为子类的对象,他原来执行的行为依然保持不变,那么这样的程序才符合里氏替换原则,否则违背了里氏替换原则。http://blog.csdn.net/wangyang1354/article/details/51164514 ### 依赖倒置原则 In object-oriented programming, the dependency inversion principle refers to a specific form of decoupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are reversed, thus rendering high-level modules independent of the low-level module implementation details. The principle states: > * A. High-level modules should not depend on low-level modules. Both should depend on abstractions. > * B. Abstractions should not depend on details. Details should depend on abstractions. The principle inverts the way some people may think about object-oriented design, dictating that both high- and low-level objects must depend on the same abstraction. ----WIKIPEDIA 释义(读者可以试着自己翻译下,个人感觉第二句不好翻,不过蛮有意思的): 在面向对象的程序设计中,依赖倒置原则是指解耦软件模块的特殊的形式。传统的依赖关系建立在高层次,而具体的策略设置应用在低层次上。使用依赖倒置原则,使得高层独立于底层的实现细节,依赖关系被倒置,使得低层次模块依赖于高层次模块的抽象。 原则规定: * A. 高层模块不应该依赖于低层模块,双方都要依赖于抽象类。 * B. 抽象类不应该依赖于实现细节,实现细节应该依赖于抽象。 这项原则颠覆了一些人对面向对象程序设计的认识,比如:高层和低层都应该依赖于相同的抽象。 http://blog.csdn.net/wangyang1354/article/details/51167071 ### 接口隔离原则 接口隔离原则(英语:interface-segregation principles, 缩写:ISP)指明没有客户(client)应该被迫依赖于它不使用方法。接口隔离原则(ISP)拆分非常庞大臃肿的接口成为更小的和更具体的接口,这样客户将会只需要知道他们感兴趣的方法。这种缩小的接口也被称为角色接口(role interfaces)。接口隔离原则(ISP)的目的是系统解开耦合,从而容易重构,更改和重新部署。----WIKIPEDIA 个人对于接口隔离原则的理解是: 设计接口的时候,尽量保证实现接口的那些类尽可能一致的包含着接口中的方法,避免过多的设计了接口中的方法,导致其实现类中需要实现多个完全没有用处的方法(会造成代码的冗余和混乱)。 http://blog.csdn.net/wangyang1354/article/details/51172635 ### 迪米特法则(最少知道准则) 得墨忒耳(迪米特)定律(Law of Demeter,缩写LoD)亦称为“最少知识原则(Principle of Least Knowledge)”,是一种软件开发的设计指导原则,特别是面向对象的程序设计。得墨忒耳(迪米特)定律是松耦合的一种具体案例。该原则是美国东北大学在1987年末在发明的,可以简单地以下面任一种方式总结: 1. 每个单元对于其他的单元只能拥有有限的知识:只是与当前单元紧密联系的单元; 2. 每个单元只能和它的朋友交谈:不能和陌生单元交谈; 3. 只和自己直接的朋友交谈。 这个原理的名称来源于希腊神话中的农业女神,孤独的得墨忒耳。 很多面向对象程序设计语言用"."表示对象的域的解析算符,因此得墨忒耳定律可以简单地陈述为“只使用一个.算符”。因此,a.b.Method()违反了此定律,而a.Method()不违反此定律。一个简单例子是,人可以命令一条狗行走(walk),但是不应该直接指挥狗的腿行走,应该由狗去指挥控制它的腿如何行走。----WIKIPIDIA 个人的理解: 面向对象的程序设计中,对象与对象之间尽量相互独立,具体对象的行为由具体的对象去完成,而不是由某个对象去指定另一个对象去实施行为而且是具体的行为。迪米特法则,核心的思想就是,要求我们在设计的时候,尽量避免类与类之间的耦合,弱化耦合关系可以提升复用率,但是这样的话,会产生中间的跳转类等,导致系统复杂。实际使用的过程中尽量在保证可读性与复杂性较低的情况下,按照迪米特法则去弱化类与类之间的耦合关系(高内聚、低耦合)。 http://blog.csdn.net/wangyang1354/article/details/51177866 ### 开闭原则 在面向对象编程领域中,开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查,单元测试以及诸如此类的用以确保产品使用质量的过程。遵循这种原则的代码在扩展时并不发生改变,因此无需上述的过程。 开闭原则的命名被应用在两种方式上。这两种方式都使用了继承来解决明显的困境,但是它们的目的,技术以及结果是不同的。----WIKIPEDIA 个人对于开闭原则的理解: 开闭原则相当于一个纲领性质的原则,提倡类等应该在设计完成后通过扩展的方式适应新的业务需求,而不是通过修改的方式去适应新的需求,这样的设计更加灵活、稳定。之前的五大原则是开闭原则思想的具体实现的情况。 http://blog.csdn.net/wangyang1354/article/details/51179851 ## 设计模式 ### 单例模式 #### 懒汉式单例 ```com.patterns.singleton.LazySingleton.java``` 懒汉式单例模式在第一次调用的时候进行实例化。 1. 适用于单线程环境(不推荐) > 此方式在单线程的时候工作正常,但在多线程的情况下就有问题了。如果两个线程同时运行到判断instance是否为null的if语句,并且instance的确没有被创建时,那么两个线程都会创建一个实例,此时类型Singleton1就不再满足单例模式的要求了。 2. 适用于多线程环境,但效率不高(不推荐) > 为了保证在多线程环境下我们还是只能得到该类的一个实例,只需要在getInstanceB()方法加上同步关键字sychronized,就可以了。**但**每次调用getInstanceB()方法时都被synchronized关键字锁住了,会引起线程阻塞,影响程序的性能。 3. 双重检验锁 > 为了在多线程环境下,不影响程序的性能,不让线程每次调用getInstanceC()方法时都加锁,而只是在实例未被创建时再加锁,在加锁处理里面还需要判断一次实例是否已存在。 4. 静态内部类方式 > 加载一个类时,其内部类不会同时被加载。一个类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。 由于在调用 StaticSingleton.getInstance() 的时候,才会对单例进行初始化,而且通过反射,是不能从外部类获取内部类的属性的;由于静态内部类的特性,只有在其被第一次引用的时候才会被加载,所以可以保证其线程安全性。 > 总结: > 优势:兼顾了懒汉模式的内存优化(使用时才初始化)以及饿汉模式的安全性(不会被反射入侵)。 > 劣势:需要两个类去做到这一点,虽然不会创建静态内部类的对象,但是其 Class 对象还是会被创建,而且是属于永久带的对象。 #### 饿汉式单例模式 ```com.patterns.singleton.HungrySingleton``` > 饿汉式单例类:在类初始化时,已经自行实例化。 #### 枚举类方式(推荐) ```com.patterns.singleton.EnumSingleton``` > 创建枚举默认就是线程安全的,所以不需要担心double checked locking,而且还能防止反序列化导致重新创建新的对象。保证只有一个实例(即使使用反射机制也无法多次实例化一个枚举量)。 #### 总结 一般情况下直接使用饿汉式就好了,如果明确要求要懒加载(lazy initialization)会倾向于使用静态内部类,如果涉及到反序列化创建对象时会试着使用枚举方式来实现单例 ### 工厂模式 任何可以产生对象的方法或类,都可以称之为工厂。 #### 简单工厂模式 > 简单工厂模式最大的优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。但是当需求变动的时候,需要对原有的类进行修改,违背了开放封闭原则。 #### 工厂方法模式 > 当需要增加一个新产品ProductD,只需要新建对应的FactoryD来实现生产功能即可,对原有的代码没有任何影响,非常符合**开放封闭原则**,但是由于每增加一个产品,都需要新增对应的生产工厂,导致增加额外的开发工作量。 > > 由于使用了多态,工厂方法克服了简单工厂违背的开放封闭原则的缺点,又保持了封装对象创建过程的优点。 #### 抽象工厂模式 > **抽象工厂模式**提供一个创建一**系列**相关或相互依赖对象的接口,而无需制定他们具体的类。抽象工厂接口,应该包含所有的产品创建的抽象方法,我们可以定义实现不止一个接口,一个工厂也可以生产不止一种产品类,和工厂方法模式一样,**抽象工厂模式**同样实现了**开发封闭原则** ### 策略模式 `com.patterns.strategy` ![](https://gitee.com/ken010127/doc_manage/raw/master/img/20210421144158.png) ### 调停者(mediator)【中介者】---MQ 是一种行为设计模式, 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。 对外是Facade 中介者模式包含以下主要角色。 1. 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。 2. 具体中介者(Concrete Mediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。 3. 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。 4. 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。 ![](https://gitee.com/ken010127/doc_manage/raw/master/img/20210421164523.png) ### 装饰器 decorator ### 责任链 Chain of Responsibility ### 观察者模式 Observer 事件处理模型 ![](https://gitee.com/ken010127/doc_manage/raw/master/img/20210421182232.png) ### 享元模式 Flyweight 重复利用对象 String对象使用的就是享元模式 ### 代理模式 Proxy 代理行为与代理对象 静态代理 代理的对象固定 `com.patterns.proxy.staticproxy` 动态代理 【asm、cglib、spring aop】 `com.patterns.proxy.dynamicproxy` jdk动态代理执行过程 ![](https://gitee.com/ken010127/doc_manage/raw/master/img/20210422114527.png) ### 迭代器 Iterator 容器与容器的遍历 ### 访问者 Vistor 在结构不变的情况下动态改变对于内部元素的动作 ![](https://gitee.com/ken010127/doc_manage/raw/master/img/20210422150235.png) ### 构建器模式 Builder 构建复杂的对象,不同的构建器可以构建不同的对象 例子:游戏地图,每个地图有自己的构建器,构建器实现自己的地形。地形中的山、树、河都是固定的对象,看你怎样在构建器中摆设这些对象。 ### 适配器模式 Adapter ### 桥接模式 Bridge 分离抽象与具体 用聚合方式连接(桥)抽象和具体 ### 命令模式 Command 别名: Action / Transaction ### 备忘录模式 memento 记录快照(瞬间状态) 存盘