谢立新 | 2021软件代码开发技术作业二 | 读书笔记--软件设计原则、设计模式

这个作业属于哪个课程 2021软件代码开发技术
这个作业要求在哪里 读书笔记-软件设计原则和设计模式
这个作业的目标 学习软件设计原则、设计模式

参考资料

《设计模式(JAVA版)》韩敬海主编

一、设计原则

1、单一职责原则【Single Responsibility Principle,SRP】

  • 定义:There should never be more than one reason for a class to change.

一个类,应该只专注于做一件事情,应该只有一个职责;

优点:1、降低类的复杂性;2、提高类的可读性;3、提高代码的可维护性和复用性;4、降低因变更引起的风险;

2、里氏替换原则【Liskov Substitution Principle,LSP】

  • If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of S, the behavior of P is unchanged when o1 is substituted for o2 then T is a subtype of S.

在父类对象出现的地方,可以使用它的子类对象进行替换而不产生错误;

3、依赖倒置原则【Dependence Inversion Principle,DIP】

  • High level modules should not depend upon low level modules. Both should depend upon abstractions. abstractions should not depend upon details. Details should depend upon abstractions.

高层模块不依赖于底层模块,它们都依赖于抽象;细节应该依赖抽象而不是相反;

4、接口隔离原则【Interface Segregation Principle,ISP】

  • The dependency of one class to another one should depend on the smallest possible interface.

一个类对另外一个类的依赖性应当是建立在最小的接口上的,使用多个专门的接口比使用单一的总接口要好;

5、迪米特法则 【Law of Demeter,LoD/Least Knowledge Principle,LKP】

一个对象应当对其他对象尽可能少的了解,即一个类应该对自己需要耦合或者调用的类知道得最少;

6、开闭原则【Open-Closed Principle,OCP】

  • Software entities should be open for extension, but closed for modification.

一个软件实体(如类、模块、函数)应当对外扩展开放,对修改关闭;

优点:1、提高复用性;2、提高可维护性;3、提高灵活性;4、易于测试;

二、创建型模式

1、单例模式【Singleton Pattern】

  • Ensure a class has only one instance, and provide a global point of access to it.

  • 一个类只有一个实例,而且自行实例化并向整个系统提供这个实例;

(1)饿汉式单例类:类加载时,就进行对象实例化;

public class Singleton{
    private static Singleton m_instance = new Singleton();
    // 构造方法私有,保证外界无法直接实例化
    private Singleton(){}
    // 通过该方法获得实例对象
    public static Singleton getInstance(){
        return m_instance;
    }
}

(2)懒汉式单例类:第一次引用类时,才进行对象实例化;

public class Singleton{
    private static Singleton _instance = null;
    // 构造方法私有,保证外界无法直接实例化
    private Singleton(){}
    // 方法同步
    public synchronized static Singleton getInstance(){
        if(_instance == null){
            _instance = new Singleton();
        }
        return _instance;
    }
}

优点:

(1)减少内存的开支,特别是一个对象需要频繁地创建、销毁,而且创建或销毁的性能又无法优化时;

(2)减少系统的性能开销,当一个对象的产生需要比较多资源时,如读取配置、产生其他依赖对象时,则可以通过在启用时直接产生一个单例对象,然后用永久驻留内存的方式来解决;

(3)避免对资源的多重占用(如一个写文件动作,由于只有一个实例存在于内存中,避免了对同一个资源文件的同时操作);

(4)可以在系统设置全局的访问点,优化和共享资源访问(如可以设计一个单例类,负责所有数据表的映射处理);

缺点:

(1)无法创建子类,扩展困难;

(2)对测试不利;

(3)与单一职责原则有冲突【单例模式把“要单例”和业务逻辑融合在一起】;

2、工厂方法模式【Factory Method Pattern】

【Virtual Constructor / Polymorphic Factory】

工厂模式:简单工厂、工厂方法、抽象工厂模式;

  • Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

  • 定义一个用于创建对象的工厂接口,将实际创建工作推迟到子类中;

四个角色:

(1)抽象工厂(Creator)角色:工厂方法模式的核心,与应用系统无关,任何在创建对象的工厂类必须实现这个接口;
(2)具体工厂(Concrete Creator)角色:实现了抽象工厂接口,含有与应用密切相关的逻辑,并且受到应用程序的调用以创建产品对象;
(3)抽象产品(Product)角色:负责定义产品的共性,实现对产品最抽象的定义;
(4)具体产品(Concrete Product)角色:实现抽象产品角色所声明的接口,工厂方法模式所创建的每一个对象都是某个具体产品角色的实例;

优点:

(1)良好的封装性,代码结构清晰;

(2)优秀的可扩展性;

(3)屏蔽产品类;

(4)工厂方法模式是典型的解耦框架;

3、抽象工厂模式【Abstract Factory Pattern】

  • Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

为创建一组相关或相互依赖的对象提供一个接口,而且无须指定他们的具体类;

四个角色:

(1)抽象工厂(Abstract Factory)角色:是抽象工厂模式的核心,与应用系统无关,任何创建对象的工厂必须实现这个接口;
(2)具体工厂(Concrete Factory)角色:实现了抽象工厂接口,含有选择合适的产品对象的逻辑,并且受到应用程序的调用以创建产品对象;
(3)抽象产品(Abstract Product)角色:负责定义产品的共性,实现对产品最抽象的定义;
(4)具体产品(Concrete Product)角色:实现抽象产品角色所声明的接口,抽象工厂模式所创建的任何产品对象都是某个具体产品角色的实例;

4、建造者模式【Builder Pattern】

  • Separate the construction of a complex object from its representation so that the same construction process can create different representations.

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示;

四个角色:

(1)抽象建造者(Builder)角色:用于规范产品的各个组成部分,并进行抽象,一般独立于应用程序的逻辑;
(2)具体建造者(Concrete Builder)角色:实现抽象建造者中定义的所有方法,并且返回一个组建好的产品实例;
(3)产品(Product)角色:建造中的复杂对象,一个系统中会有多于一个的产品类,这些产品类并不一定有共同的接口,完全可以是不相关联的;
(4)导演者(Director)角色:负责安排已有模块的顺序,然后告诉BUilder开始建造;

优点:

(1)封装性,使用建造者模式可以使客户端不必知道产品内部组成的细节;

(2)建造者独立,容易扩展;

(3)可以对建造过程逐步细化,而不对其他的模块产生任何影响;

5、原型模式【Prototype Pattern】

  • Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象;

三个角色:

(1)客户(Client)角色:提出创建对象的请求;
(2)抽象原型(Prototype)角色:是一个抽象角色,通常由一个Java接口或抽象类实现,给出所有的具体原型类所需的接口;
(3)具体原型(Concrete Prototype)角色:是被复制的对象,必须实现抽象原型接口;

优点:

(1)性能优良:原型模式是在内存二进制流的复制,要比直接new一个对象性能好,特别是在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点;

(2)逃避构造函数的约束:这既是优点也是缺点,直接在内存中赋值,构造函数是不会执行的,因此减少了约束,需要在实际应用时进行权衡考虑;

三、结构型模式

1、代理模式【Proxy Pattern】

  • Provide a surrogate or placeholder for another object to control access to it;
  • 为其他对象提供一种代理以控制对这个对象的访问;

三个角色:

(1)抽象主题(Subject)角色:是真实主题和代理主题的共同接口,以便在任何可以使用真实主题的地方都可以使用代理主题;
(2)代理主题(Proxy Subject)角色:也叫做委托类、代理类,负责控制对真实主题的引用,负责在需要的时候创建或删除真实主题对象,并且在真实主题角色处理完毕前后做预处理和善后处理工作;
(3)真实主题(Real Subject)角色:也叫做被委托角色、被代理角色,是业务逻辑的具体执行者;

代理模式的种类:

(1)远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局部代表对象;这个不同的地址空间可以是在本机器中,也可以在另一台机器中;
(2)虚拟(Virtual)代理:有时需要创建一些消耗较多资源的对象,可以首先创建代理对象,而将真实对象的创建延迟;例如,加载一个很大的图片,可以通过图片的代理来代替真正的图片;
(3)保护(Protect or Access)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限;
(4)缓存(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果;
(5)同步(Synchronization)代理使几个用户能够同时使用一个对象而没有冲突;
(6)智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,例如,记录访问的流量和次数等;

优点:

(1)职责清晰:真实的角色实现实际的业务逻辑,不用关心其他非本职的事务,通过后期的代理完成附加的事务,附带的结果就是编程简洁清晰;

(2)高扩展性:具体主题角色随需求不同可能有很多种,但只要实现了接口,代理类就完全可以在不做任何修改的情况下代理各种真实主题角;

(3)智能化:代理类可以在运行时才确定需要去代理的真实主题,这是一种强大的功能;

2、装饰模式【Decorator Pattern】

  • Attach additional responsibilities to an object dynamically keeping thesame interface. Decorators provide a flexible alternative to subclassing forextending functionality.
  • 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活

四个角色:

(1) 抽象构件(Component)角色:该角色用于规范需要装饰的对象(原始对象);
(2)具体构件(Concrete Component)角色:该角色实现抽象构件接口,定义一个需要装饰的原始类;
(3)装饰(Decorator)角色:该角色持有一个构件对象的实例,并定义一个与抽象构件接口一致的接口;
(4)具体装饰(Concrete Decorator)角色:该角色负责对构件对象进行装饰;

优点:

(1)装饰类和被装饰类可以独立发展,而不会相互耦合;即 Component 类无须知道Decorator类,Decorator类是从外部来扩展Component类的功能,而Decorator也不用知道具体的构件;

(2)装饰模式是继承关系的一个替代方案;装饰类Decorator,不管装饰多少层,返回的对象还是Component;

(3)装饰模式可以动态地扩展一个实现类的功能;

缺点:多层的装饰是比较复杂的;

3、适配器模式【Adapter Pattern】

  • Convert the interface of a class into another interface clients expect.Adapter lets classes work together that couldn't otherwise because ofincompatible interfaces.
  • 将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作;

三个角色:

(1)目标(Target)角色:该角色定义要转换成的目标接口;
(2)源(Adaptee)角色:需要被转换成目标角色的源角色;
(3)适配器(Adapter)角色:该角色是适配器模式的核心,其职责是通过继承或是类关联的方式,将源角色转换为目标角色

优点:

(1)适配器模式可以让两个没有任何关系的类在一起运行;

(2)增加了类的透明性;

(3)提高类的复用度;

(4)增强代码的灵活性;

4、组合模式【Composite Pattern】

  • Compose objects into tree structures to represent part-whole hierarchies.Composite lets clients treat individual objects and compositions of objectsuniformly.
  • 将对象组合成树形结构以表示“部分—整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性;

三个角色:

(1)抽象构件(Component)角色:该角色定义参加组合对象的共有方法和属性,规范一些默认的行为接口;
(2)叶子构件(Leaf)角色:该角色是叶子对象,其下没有其他的分支,定义出参加组合的原始对象的行为;
(3)树枝构件(Composite)角色:该角色代表参加组合的、其下有分支的树枝对象,它的作用是将树枝和叶子组合成一个树形结构,并定义出管理子对象的方法,如add()、remove()等;

优点:

(1)高层模块调用简单;一棵树形机构中的所有节点都是 Component,局部和整体对调用者来说没有任何区别,即高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码;

(2)节点自由增加;使用组合模式后,如果想增加一个树枝节点、树叶节点只需要找到其父节点即;

缺点:

(1)不易控制树枝构件的类型;

(2)不易使用继承的方法来增加新的行为;

5、桥梁模式【Bridge Pattern】

  • Decouple an abstraction from its implementation so that the two can vary independently.
  • 将抽象和实现解耦,使得两者可以独立地变化;

四个角色:

(1)抽象化(Abstraction)角色:该角色抽象化的给出定义,并保存一个对实现化对象的引用;
(2)实现化(Implementor)角色:该角色给出实现化角色的接口,但不给出具体的实现;
(3)修正抽象化(RefinedAbstraction)角色:该角色扩展抽象化角色,它引用实现化角色并对抽象化角色进行修正;
(4)具体实现化(ConcreteImplementor)角色:该角色对实现化角色接口中的方法进行具体实现;

优点:

(1)抽象和实现分离是桥梁模式的主要特点,是为了解决继承的缺点而提出的设计模式;在该模式下,实现可以不受抽象的约束,不用绑定在一个固定的抽象层次上;

(2)实现对客户透明,客户端不用关心细节的实现,它已经由抽象层通过聚合关系完成了封装;

(3)提高灵活性和扩展性;

6、外观模式【Facade Pattern】

  • Provide a unified interface to a set of interfaces in a subsystem. Facadedefines a higher-level interface that makes the subsystem easier to use.
  • 要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行;外观模式提供一个高层次的接口,使得子系统更易使用;

两个角色:

(1)外观(Facade)角色:客户端可以调用该角色的方法,该角色知晓相关子系统的功能和责任;正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统,即该角色没有实际的业务逻辑,只是一个委托类;

(2)子系统(Subsystem)角色:可以同时有一个或多个子系统,每一个子系统都不是一个单独的类,而是一个类的集合;子系统不知道外观角色的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已;

优点:

(1)减少系统的相互依赖,所有的依赖都是对Façade对象的依赖,与子系统无关;

(2)提高灵活性,不管子系统内部如何变化,只要不影响Facade对象,任何活动都是自由的;

(3)提高安全性,Facade中未提供的方法,外界就无法访问,提高系统的安全性;

缺点:最大的缺点是不符合开闭原则;

7、享元模式【Flyweight Pattern】

  • Use sharing to support large numbers of fine-grained objects efficiently.
  • 使用共享对象可有效地支持大量的细粒度的对象;
享元模式是以共享的方式高效地支持大量的细粒度对象;享元对象能做到共享的关键是区分内部状态(Internal State)和外部状态(External State);
(1)内部状态是存储在享元对象内部的、可以共享的信息,并且不会随环境改变而改变;
(2)外部状态是随环境改变而改变且不可以共享的状态;享元对象的外部状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部;

四个角色:

(1)抽象享元(Flyweight)角色:该角色对享元类进行抽象,需要外部状态的操作可以通过参数的形式将外部状态传入;
(2)具体享元(ConcreteFlyweight)角色:该角色实现抽象享元定义的业务,注意享元对象的内部状态必须与环境无关,从而使得享元对象可以在系统内共享;
(3)享元工厂(FlyweightFactory)角色:该角色就是构造一个池容器,负责创建和管理享元角色,并提供从池容器中获得对象的方法,保证享元对象可以被系统适当的共享;当一个客户端对象请求一个享元对象时,享元工厂角色会检查系统中是否已经有一个符合要求的享元对象;如果已经有了,享元工厂则提供这个已有的享元对象;否则创建一个合适的享元对象;
(4)客户端(Client)角色:该角色需要自行存储所有享元对象的外部状态;

优点:大幅减少内存中对象的数量,降低程序内存的占用,提高性能;

缺点:

(1)增加了系统的复杂性,需要分出外部状态和内部状态,而且内部状态具有固化特性,不应该随外部状态改变而改变,这使得程序的逻辑复杂化;

(2)将享元对象的状态外部化,而读取外部状态使得运行时间变长;

四、行为型模式

1、模板方法模式【Template Method Pattern】

  • Define the skeleton of an algorithm in an operation, deferring some stepsto subclasses. Template Method lets subclasses redefine certain steps of analgorithm without changing the algorithm's structure.
  • 定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤;

两个角色:

(1)抽象模板(Abstract Template)角色:该角色定义一个或多个抽象操作,以便让子类实现;这些抽象操作是基本操作,是一个顶级逻辑的组成步骤。还需要定义并实现一个或几个模板方法,这些模板方法一般是具体方法,即一个框架,实现对基本方法的调度,完成固定的逻辑;
(2)具体模板(Concrete Template)角色:该角色实现抽象模板中定义的一个或多个抽象方法,每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法的不同实现,从而使得顶级逻辑的实现各不相同;

优点:

(1)封装不变的部分,扩展可变部分;不变的部分封装到父类中实现,而可变的部分则可以通过继承进行扩展;

(2)提取公共部分代码,便于维护;将公共部分的代码抽取出来放在父类中,维护时只需要修改父类中的代码;

(3)行为由父类控制,子类实现;模板方法模式中的基本方法是由子类实现的,因此子类可以通过扩展增加相应的功能,符合开闭原则;

2、命令模式【Command Pattern】

  • Encapsulate a request as an object, thereby letting you parameterize clientswith different requests, queue or log requests, and support undoableoperations.
  • 将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能;

四个角色:

(1)命令(Command)角色:该角色声明一个给所有具体命令类的抽象接口,定义需要执行的命令;
(2)具体命令(Concrete Command)角色:该角色定义一个接收者和行为之间的弱耦合,实现命令方法,并调用接收者的相应操作;
(3)调用者(Invoker)角色:该角色负责调用命令对象执行请求;
(4)接收者(Receiver)角色:该角色负责具体实施和执行一个请求;

优点:

(1)类间解耦;调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需要调用Command中的execute()方法即可,不需要了解是哪个接收者执行;

(2)可扩展性;Command 的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合;

(3)命令模式结合其他模式会更优秀;命令模式可以结合责任链模式,实现命令族解析任务,结合模板方法模式,则可以减少Command子类的膨胀问题;

缺点:使用命令模式可能会导致系统中出现过多的具体命令类,因此需要在项目中慎重考虑使用;

3、责任链模式【Chain of Responsibility Pattern】

  • Avoid coupling the sender of a request to its receiver by giving more thanone object a chance to handle the request. Chain the receiving objects andpass the request along the chain until an object handles it.
  • 使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止;

两个角色:

(1)抽象处理者(Handler)角色:该角色对请求进行抽象,并定义一个方法以设定和返回对下一个处理者的引用;
(2)具体处理者(Concrete Handler)角色:该角色接到请求后,可以选择将请求处理掉,或者将请求传给下一个处理者;由于具体处理者持有对下一个处理者的引用,因此,如果需要,具体处理者可以访问下一个处理者;

优点:

(1)责任链模式将请求和处理分开,请求者不知道是谁处理的,处理者可以不用知道请求的全貌;

(2)提高系统的灵活性;

缺点:

(1)降低程序的性能,每个请求都是从链头遍历到链尾,当链比较长的时候,性能会大幅下降;

(2)不易于调试,由于采用了类似递归的方式,调试的时候逻辑比较复杂;

4、策略模式【Strategy Pattern】

  • Define a family of algorithms, encapsulate each one, and make theminterchangeable.
  • 定义一组算法,将每个算法都封装起来,并且使它们之间可以互换;

三个角色:

(1)环境(Context)角色:该角色也叫上下文角色,起到承上启下的作用,屏蔽高层模块对策略、算法的直接访问,它持有一个Strategy类的引用;
(2)抽象策略(Strategy)角色:该角色对策略、算法进行抽象,通常定义每个策略或算法必须具有的方法和属性;
(3)具体策略(Concrete Strategy)角色:该角色实现抽象策略中的具体操作,含有具体的算法;

优点:

(1)策略类的等级结构定义了一个算法或行为族,恰当地使用继承可以把公共的代码移到父类中,从而避免代码重复

(2)提供了可以替换继承关系的办法;

(3)可以避免使用多重条件转移语句;

缺点:

(1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类;

(2)策略模式造成很多的策略类;

5、迭代器模式【Iterator Pattern】

  • Provide a way to access the elements of an aggregate object sequentiallywithout exposing its underlying representation.
  • 提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节;

四个角色:

(1)抽象迭代器(Iterator)角色:该角色负责定义访问和遍历元素的接口;
(2)具体迭代器(Concrete Iterator)角色:该角色实现Iterator接口,完成容器元素的遍历;
(3)抽象聚集(Aggregate)角色:该角色提供创建迭代器角色的接口;
(4)具体聚集(Concrete Aggregate)角色:该角色实现抽象聚集接口,创建出容纳迭代器的对象;

优点:

(1)简化了访问容器元素的操作,具备一个统一的遍历接口;

(2)封装遍历算法,使算法独立于聚集角色;客户无须知道聚集对象的类型,即使聚集对象的类型发生变化,也不会影响遍历过程;

缺点:

(1)给使用者一个序列化的错觉,从而产生错误;

(2)迭代器的元素都是Object类型,没有类型特征(JDK1.5后通过引入泛型可以解决此问题);

6、中介者模式【Mediator】

  • Define an object that encapsulates how a set of objects interact. Mediatorpromotes loose coupling by keeping objects from referring to each otherexplicitly, and it lets you vary their interaction independently.
  • 用一个中介对象封装一系列对象(同事)的交互,中介者使各对象不需要显式地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互;

四个角色:

(1)抽象中介者(Mediator)角色:该角色定义出同事对象到中介者对象的统一接口,用于各同事角色之间的通信;
(2)具体中介者(Concrete Mediator)角色:该角色实现抽象中介者,它依赖于各个同事角色,并通过协调各同事角色实现协作行为;
(3)抽象同事(Colleague)角色:该角色定义出中介者到同事对象的接口,同事对象只知道中介者而不知道其余的同事对象;
(4)具体同事(Concrete Colleague)角色:该角色实现抽象同事类,每一个具体同事类都清楚自己在小范围内的行为,而不知道大范围内的目的;

优点:

(1)减少类间的依赖,将原有的一对多的依赖变成一对一的依赖,使得对象之间的关系更易维护和理解;

(2)避免同事对象之间过度耦合,同事类只依赖于中介者,使同事类更易被复用,中介类和同事类可以相对独立地演化;

(3)中介者模式将对象的行为和协作抽象化,将对象在小尺度的行为上与其他对象的相互作用分开处理;

缺点:

(1)中介者模式降低了同事对象的复杂性,但增加了中介者类的复杂性;

(2)中介者类经常充满了各个具体同事类的关系协调代码,这种代码是不能复用的;

7、观察者模式【Observer Pattern】

  • Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
  • 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新

四个角色:

(1)抽象主题(Subject)角色:该角色又称为“被观察者”,可以增加和删除观察者对象;
(2)抽象观察者(Observer)角色:该角色为所有的具体观察者定义一个接口,在得到主题的通知时更新自己;
(3)具体主题(Concrete Subject)角色:该角色又称为“具体被观察者”,它将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知;
(4)具体观察者(Concrete Observer)角色:该角色实现抽象观察者所要求的更新接口,以便使自身的状态与主题的状态相协调;

优点:

(1)观察者和被观察者之间是抽象耦合;

(2)支持广播通信;

缺点:

(1)如果一个主题有多个直接或间接的观察者,则通知所有的观察者会花费很多时间,且开发和调试都比较复杂;

(2)如果在主题之间有循环依赖,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式时要特别注意这一点;

(3)如果对观察者的通知是通过另外的线程进行异步投递,系统必须保证投递的顺序执行;

(4)虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有提供相应的机制使观察者知道所观察的对象是如何发生变化;

8、备忘录模式【Memento Pattern】

  • Without violating encapsulation,capture and externalize an object'sinternal state so that the object can be restored to this state later.
  • 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样,以后就可以将该对象恢复到原先保存的状态;

三个角色:

(1)发起人(Originator)角色:该角色记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备忘数据;
(2)备忘录(Memento)角色:该角色负责存储发起人角色的内部状态,在需要时提供发起人需要的内部状态数据;
(3)负责人(Caretaker)角色:该角色对备忘录角色进行管理、保存和提供备忘录;

9、访问者模式【Visitor Pattern】

  • Represent an operation to be performed on the elements of an objectstructure. Visitor lets you define a new operation without changing theclasses of the elements on which it operates.
  • 封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作;

五个角色:

(1)抽象访问者(Visitor)角色:该角色声明一个或多个访问操作,定义访问者可以访问哪些元素;
(2)具体访问者(Concrete Visitor)角色:该角色实现抽象访问者角色中的各个访问操作;
(3)抽象元素(Element)角色:该角色声明一个接受操作,接受一个访问者对象;
(4)具体元素(Concrete Element)角色:该角色实现抽象元素中的接受操作;
(5)结构对象(Object Structure)角色:该角色有以下责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素,也可以设计一个复合对象或者一个集合,如List或Set;

优点:

(1)使得增加新的操作变得很容易,增加新的操作只需要增加新的访问者类;

(2)访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个元素类中;

(3)访问者模式可以跨过几个类的等级结构访问属于不同等级结构的成员类;

(4)累积状态;每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己内部,而不是分散到很多的元素对象中,益于系统的维护;

缺点:
(1)增加新的元素类变得很困难;

(2)破坏封装;

(3)违背了依赖倒置原则;

10、状态模式【State Pattern】

  • Allow an object to alter its behavior when its internal state changes. Theobject will appear to change its class.
  • 当一个对象内在状态改变时允许改变行为,这个对象看起来像改变了其类型;

三个角色:

(1)抽象状态(State)角色:该角色用以封装环境对象的一个特定状态所对应的行为;
(2)具体状态(Concrete State)角色:该角色实现环境的一个状态所对应的行为;
(3)环境(Context)角色:该角色定义客户端需要的接口,并负责具体状态的切换。它会保留一个具体状态类的实例,该实例给出环境对象的现有状态;

优点:

(1)结构清晰;

(2)遵循设计原则;

(3)封装性非常好;

缺点:子类太多,不易管理;

11、解释器模式【Interpreter Pattern】

  • Given a language, define a representation for its grammar along with aninterpreter that uses the representation to interpret sentences in thelanguage.
  • 给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子;

五个角色:

(1)抽象表达式(Abstract Expression)角色:该角色声明一个所有的具体表达式角色都需要实现的抽象接口,该接口主要是一个解释操作interpret()方法;
(2)终结符表达式(Terminal Expression)角色:该角色实现了抽象表达式角色所要求的接口,文法中的每一个终结符都有一个具体终结表达式与之对应;
(3)非终结符表达式(Nonterminal Expression)角色:该角色是一个具体角色,文法中的每一条规则都对应一个非终结符表达式类;
(4)环境(Context)角色:该角色提供解释器之外的一些全局信息;
(5)客户端(Client)角色:该角色创建一个抽象语法树,调用解释操作;

优点:

(1)简单的语法分析工具;

(2)扩展性,修改语法规则只要修改相应的非终结符表达式即可,若扩展语法,则只要增加非终结符类即可;

缺点:

(1)会引起类膨胀;每个语法都要产生一个非终结符表达式,语法比较复杂时就可能产生大量的类文件,不易维护;

(2)采用递归调用方法;每个非终结符表达式只关心与自己有关的表达式,每个表达式需要知道最终的结果,必须一层一层地剥茧,无论是面向过程的语言还是面向对象的语言,递归都是在必要条件下使用的,不易调试且影响效率;

五、心得体会

  • 在阅读设计模式的书籍过程中,我意识到这些设计模式应该要在实践中运用;而在实践中,我也接触过其中几种设计模式,当初不知道这种方法的名字叫什么,直到阅读了设计模式的知识,才更深入的理解了这些设计方法;在软件设计过程中,遵循规范的软件设计原则和设计模式可以帮助我们设计出更好的软件,在后期维护中也更容易。希望在不断的实践中将这些理论知识转化为自己的软件设计习惯。
posted @ 2021-03-17 23:12  ecochap  阅读(138)  评论(0)    收藏  举报