文章目录
【注意】以下UML类图中,类之间的关系可能不正确或者不准确,一定要相信自己的判断!
概览
开闭原则:软件实体应当对扩展开放,对修改关闭。
-
抽象化是开闭原则的关键
-
相对稳定的抽象层 + 灵活的具体层
-
对可变性封装原则(Principle of Encapsulation of Variation, EVP):找到系统的可变因素并将其封装起来
创建型模式
模式名称 | 定 义 |
---|---|
简单工厂模式 (Simple Factory Pattern) | 定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。 |
工厂方法模式 (Factory Method Pattern) | 定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。 |
抽象工厂模式 (Abstract Factory Pattern) | 提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。 |
建造者模式 (Builder Pattern) | 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 |
原型模式 (Prototype Pattern) | 使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。 |
单例模式 (Singleton Pattern) | 确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。 |
简单工厂模式
简单工厂模式是通过定义一个工厂类,工厂通过参数不同,从而返回不同类的实例,实例通常有不同的父类。其只要传入正确的参数,就可以获得所需的实例对象。
从上图可见,简单工厂模式的结构是:首先定义抽象类/接口,对抽象类/接口进行继承/实现,生成子类;在工厂类中创建对应产品类,并且工厂类对产品类有依赖关系。
简单工厂模式还有一种简化版本,可以将工厂类和抽象类/接口进行合并,将工厂方法放在抽象类/接口中,直接调用抽象类/接口就可以生成对应子类。
简单工厂模式不满足开闭原则。
工厂方法模式
工厂方法模式定义了一个创建对象的接口(抽象工厂类),然后让子类(具体工厂类)决定实例化的类。
工厂模式中,是将工厂进行了分离。首先实现抽象工厂,然后在具体工厂对功能进行了实现,然后在具体工厂中创建产品类的实例并返回。
工厂方法中可以将产品类中的方法放进工厂中,从而可以在不对产品进行实例化的情况下,对产品方法进行调用,从而简化使用。
工厂模式满足开闭原则。
抽象工厂模式
抽象工厂模式提供了一个创建一系列相关或互相依赖对象的接口,其对抽象工厂进行实现时是按照工厂生产的产品类型分别对工厂进行实现。
抽象工厂模式与工厂方法模式类似,都是用抽象工厂实现具体工厂。但其不同点在于抽象工厂模式中具体工厂是按照族/类来实现的,就像两个企业都能生产冰箱、电视机、彩电,但是两家企业生产的工厂是不同的。**但是抽象工厂模式存在一个问题,那就是当企业想要拓展生产线,开始生产手机时,会发现抽象工厂中没有这个抽象方法,需要对抽象工厂进行修改。**而工厂方法模式则不存在这种问题,因为工厂模式实际相当于所有生产线都是分开的,而抽象工厂模式是对这些生产线分门别类地进行了打包。
抽象工厂模式**部分符合(不完全符合)**开闭原则。
建造者模式
建造者模式是将一个复杂对象的构建与其表示进行分离,使得同样的构建过程可以创建不同的表示。
建造者模式实际上是将复杂个体进行分解,分别创建产品的各个部分,完成创建后再返回结果。根据这样的模块化构造,可以使创建的产品各不相同(对buildPartA等函数的实现不同)。
建造者模式可以方便地替换具体建造者或增加新的具体建造者,符合开闭原则。
原型模式
原型模式可以通过复制对象原型来创建新的对象。
原型模式实际上就是实现了拷贝函数。但需注意,拷贝也分浅拷贝和深拷贝。此外,原型模式中可以使用原型管理器,通过原型管理器来存储和取出对象(哈希表)。
由于在对已有类进行拓展修改(增加方法)后,会导致需要修改源代码,不符合开闭原则。
单例模式
单例模式是用于确保一个类只有一个实例,并提供一个全局访问点从而访问该实例。
单例模式就像垃圾站,一个操作系统只能有一个垃圾站。如果没有,那你在找的时候,系统就会创建出来。
单例模式还分为饿汉式单例和懒汉式单例。饿汉式单例是指在实现类时就对类变量进行实例化,懒汉式单例是指在调用获取函数时才对类变量进行实例化(延迟实现)。饿汉式单例不用考虑多线程访问,懒汉式要考虑。
单例模式由于缺少抽象类,所以在对类方法进行拓展时,需要修改类,违反了开闭原则。
结构型模式
模式名称 | 定 义 |
---|---|
适配器模式 (Adapter Pattern) | 将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。 |
桥接模式 (Bridge Pattern) | 将抽象部分与它的实现部分解耦,使得两者都能够独立变化。 |
组合模式 (Composite Pattern) | 组合多个对象形成树形结构,以表示具有部分-整体关系的层次结构。组合模式让客户端可以统一对待单个对象和组合对象。 |
装饰模式 (Decorator Pattern) | 动态地给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案。 |
外观模式 (Facade Pattern) | 为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 |
享元模式 (Flyweight Pattern) | 运用共享技术有效地支持大量细粒度对象的复用。 |
代理模式 (Proxy Pattern) | 给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。 |
适配器模式
适配器模式可以将一个类的接口转换为另一个接口。
类适配器:
类适配器是对需要适配的类进行继承,对调用接口进行实现。
对象适配器:
对象适配器是对调用接口进行实现,在适配器中调用需要适配的类(需适配的类在生成适配器时放入适配器)。
适配器模式还分为缺省适配器和双向适配器。缺省适配器是当不需要对调用对象所有方法进行实现时,可以先使用抽象类对接口进行实现,并在抽象类中将各个方法提供空方法,然后再对抽象类进行继承,从而覆盖实现特定的方法。双向适配器是利用一个适配器类对多个需要适配类进行适配。
适配器模式符合开闭原则。
桥接模式
桥接模式可以将抽象部分和实现部分解耦,使得两者能够独立变化。
桥接模式就是说,可以把多个可以互相组合的东西分别解耦,并在其中一类类中建立一座“桥”,从而实现对各类的调用。其实我觉得下图更形象地解答了桥接模式的意义。
桥接模式将角色分为两个部分,实现部分负责具体的业务,抽象部分是通过桥对具体业务的调用。
桥接模式可以任意扩展两个维度中的一个维度,不需要修改原有代码,符合开闭原则。
组合模式
组合模式可以用多个对象形成树形结构,从而来表现层次关系。
组合模式中要实现树形结构,决定了树中的非叶子节点和叶子节点需要继承同一父类,在非叶子节点中还要可以创建子类。
组合模式中可以方便地扩展节点,符合开闭原则。
装饰模式
装饰模式是动态地对一个对象增加额外职责。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kkgTvaEL-1650453856925)(…/AppData/Roaming/Typora/typora-user-images/image-20220420111000153.png)]
装饰模式实际上就是对已有的抽象类进行一个继承生成一个新的抽象类,通过该抽象类可以增加一些新的功能或者对象。需要注意的是抽象类既要继承抽象构件,又要包含一个抽象构件的指针,因为抽象装饰类实际上还是对够构件进行了一个装饰,既然是装饰那你得有原先的物件啊。
装饰模式分为透明装饰模式和半透明装饰模式。其中,透明装饰模式是在使用装饰模式时,所有对象都定义为构件的指针,不区分装饰前后的指针。半透明装饰模式是指在使用装饰模式时,需要区分构建和装饰后的指针,将构件传入装饰中。
装饰模式可以更具需求增加新的具体构件和具体装饰,符合开闭原则。
外观模式
外观模式是为子系统的一组接口提供了统一的入口,即其定义了一个高层接口。
外观模式很简单,就是把子系统进行了一个打包。但是需要注意的是,以上的外观模式是违背开闭原则的,所以又提出了抽象外观类,在具体外观类和客户端间加了一层抽象类,从而解决了该问题。
外观模式还可以和单例模式结合,从而保证只有一个入口。
无抽象外观类的外观模式违背开闭原则,有抽象类的不违背开闭原则。
享元模式
享元模式是通过共享来是来实现对对象的复用。
享元模式的一个经典案例就是Java中String类型的实现,可以把他的实现比作活字印刷术,需要某个字母就用对应的印章印上去,没有对应的印章那就重新刻一个。
在实现享元模式时,可以将工厂模式、单例模式和享元模式一起进行共用。
享元模式还分为单纯享元模式和复合享元模式。单纯享元模式就是全部的享元都是单独使用的,而复合享元则是存在一种可以将部分享元进行打包使用的享元。
代理模式
代理模式是给某一个对象提供一个代理或占位符,通过代理对象来控制对原对象的访问。
代理模式实际上就是对需要使用的对象进行了一次套皮,在对真正的对象进行套皮时还添加了其他功能,被调用的对象指针需要在代理中有储存。
代理模式可以对很好地更换代理类,无需修改源代码,符合开闭原则。
行为型模式
模式名称 | 定 义 |
---|---|
职责链模式 (Chain of Responsibility Pattern) | 避免将一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求。将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止。 |
命令模式 (Command Pattern) | 将一个请求封装为一个对象,从而让你可以用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。 |
解释器模式 (Interpreter Pattern) | 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 |
迭代器模式 (Iterator Pattern) | 提供一种方法顺序访问一个聚合对象中的各个元素,且不用暴露该对象的内部表示。 |
中介者模式 (Mediator Pattern) | 定义一个对象来封装一系列对象的交互。中介者模式使各对象之间不需要显式地相互引用,从而使其耦合松散,而且让你可以独立地改变它们之间的交互。 |
备忘录模式 (Memento Pattern) | 在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。 |
观察者模式 (Observer Pattern) | 定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都得到通知并被自动更新。 |
状态模式 (State Pattern) | 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。 |
策略模式 (Strategy Pattern) | 定义一系列算法,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法可以独立于使用它的客户变化。 |
模板方法模式 (Template Method Pattern) | 定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类不改变一个算法的结构即可重定义该算法的某些特定步骤。 |
访问者模式 (Visitor Pattern) | 表示一个作用于某对象结构中的各个元素的操作。访问者模式让你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 |
职责链模式
职责链模式可以避免将请求发送者和接收者耦合,让多个对象都有机会处理请求。
职责链模式其实定义较为简单,他的实现就是说在自己职责范围内的事进行处理,不在自己职责范围内的事就传递下去,让其他对象来处理。上图中,successor存储的是下一级的处理对象。
职责链模式在实现具体处理对象时可以进行替换,符合开闭原则。
命令模式
命令模式是将一个请求封装成一个对象,从而可以用不同请求对客户进行参数化。
命令模式就是将命令进行一个封装,然后通过封装的命令调用发送给接受者。
命令模式可以很好的对具体命令进行更换,所以符合开闭原则。
解释器模式
解释器模式就是通过解释器解释语言中的句子。
解释器模式实际上还是建一颗树,通过建树然后可以递归的对语句进行解释。上图有所简化,下图更好。
解释器模式添加新的解释式方便,符合开闭原则。
迭代器模式
迭代器模式就是提供了一种方法,既可以顺序访问一个聚合对象中的各个元素,又可以不用暴露该对象的内部表示。
迭代器模式实际上就是对遍历的封装,其意义在于用户不能直接看到对象的序号,在迭代器中实际上保存了列表的指针用于迭代。
迭代器模式引入了抽象层,在增加新的聚合类和迭代器类时都较为方便,故无需修改原有代码,符合开闭原则。
中介者模式
中介者模式可以定义一个对象来封装一系列对象的交互。
中介者中存储有同事,当同事A发送消息时,会通知中介者,中介者会对自己有的同事进行一个遍历,然后把信息发送给对应的同事。
中介者模式实现了星型结构的交互,可以将同事之间进行一个解耦,比较符合开闭原则。
备忘录模式
备忘录模式是指在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便恢复。
备忘录模式实际上就是对当前状态进行了一个镜像备份,当然除了备份以外,还有一个管理者用于管理镜像。
备忘录模式可以对信息进行封装并回滚,但是可能消耗大量资源。
观察者模式
观察者模式是定义了对象之间的一对多依赖关系,从而使得在一个对象状态发生变化时,其他对象状态也自动更新。
观察者模式实际上就是当一个对象进行一个动作时,将会调用目标类(控制中心),从而遍历通知其他观察者进行相应动作。
观察者模式新增具体观察者无需需修改原有代码,在具体观察者和观察目标不存在关联目标时,新增观察目标也方便,故符合开闭原则。
状态模式
状态模式允许一个对象在内部状态改变时,改变其行为。
状态模式中的状态是类,在对象需求改变时,会改变为不同的状态,从而在不同的状态类中可以实现不同的行为。
状态模式对开闭原则的支持不太好,在新增状态类时需要修改负责状态转换的代码。
策略模式
策略模式是将一系列算法分别封装,算法之间可以互相替换。
策略模式完全符合开闭原则。
模板方法模式
模板方法模式是定义一个操作的算法框架,将某些步骤延迟到子类中实现。
模板方法模式是对策略模式一种收窄实现,他固定了算法结构,在子类中可以对算法结构中的特定算法进行特定的实现。
模板方法的实现可以采用多种方法:
- 模板方法
- 基本方法
- 抽象方法
- 具体方法
- 钩子方法
模板方法模式在添加或更换子类时无需修改源代码,符合开闭原则。
访问者模式
访问者模式表示一个作用于某对象结构中的各元素的操作,其课在不改变各元素类的前提下定义作用于这些元素的新操作。