导图社区 《软件秘笈》读书笔记
这本书概述了设计模式的必要性和分类,将设计模式分为三大类:创建型模式、结构型模式和行为型模式。书中详细解释了23个设计模式,每个模式都通过一个生活故事引入,然后是模式定义、模式分析、模式实现、设计原则和使用场合。通过这本书,可以更好地理解设计模式,并将其应用到实际项目中!
编辑于2025-03-05 17:50:38这是一本陪伴中国女性终身成长的案头书。作者结合20年女性情商培训经验,将西方经典心理学理论和中国特色的情商精神相结合,再现38个中国女性的真实案例,总结困扰女性成长过程中的15个普遍问题,如:职场不平等、打造个人品牌、情绪管理、感性消费、亲子与亲密关系等。通过情商修炼,你可以提升自己的“职商”,实现自律人生!
这本书概述了设计模式的必要性和分类,将设计模式分为三大类:创建型模式、结构型模式和行为型模式。书中详细解释了23个设计模式,每个模式都通过一个生活故事引入,然后是模式定义、模式分析、模式实现、设计原则和使用场合。通过这本书,可以更好地理解设计模式,并将其应用到实际项目中!
这是一本能够帮助读者打破常规思维,提升逻辑思维能力的书籍。它通过生动丰富的实例,深入浅出地剖析了逆转思维的精髓与运用之道,适用于各种场景,包括职场挑战、生活抉择等。通过学习本书,读者可以学会反其道而行之,将被动化为主动,将看似腐朽的事物点石成金,创造出令人惊叹的奇迹!
社区模板帮助中心,点此进入>>
这是一本陪伴中国女性终身成长的案头书。作者结合20年女性情商培训经验,将西方经典心理学理论和中国特色的情商精神相结合,再现38个中国女性的真实案例,总结困扰女性成长过程中的15个普遍问题,如:职场不平等、打造个人品牌、情绪管理、感性消费、亲子与亲密关系等。通过情商修炼,你可以提升自己的“职商”,实现自律人生!
这本书概述了设计模式的必要性和分类,将设计模式分为三大类:创建型模式、结构型模式和行为型模式。书中详细解释了23个设计模式,每个模式都通过一个生活故事引入,然后是模式定义、模式分析、模式实现、设计原则和使用场合。通过这本书,可以更好地理解设计模式,并将其应用到实际项目中!
这是一本能够帮助读者打破常规思维,提升逻辑思维能力的书籍。它通过生动丰富的实例,深入浅出地剖析了逆转思维的精髓与运用之道,适用于各种场景,包括职场挑战、生活抉择等。通过学习本书,读者可以学会反其道而行之,将被动化为主动,将看似腐朽的事物点石成金,创造出令人惊叹的奇迹!
《软件秘笈》读书笔记
四、行为型模式
责任链模式
定义
责任链模式是一种对象的行为模式。在责任链模式中,很多对象由每一个对象对其下家的引用而连接起来形成一条链
客户端应用请求在这个链上传递,直到链上的某一个对象决定处理此请求
发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使系统可以在不影响客户端的情况下动态地重新组织链和分配责任
设计原则
“开-闭”原则:责任链当中的处理节点可以动态地进行扩展
单一职责原则:每个处理节点功能单一,专注完成自身的处理行为
模式中的角色
抽象处理者角色(Handler)
定义出一个处理请求的接口
如果需要,接口可以定义出一个方法,以设定和返回下家的引用。这个角色通常由一个Java抽象类或Java接口实现
具体处理者角色(ConcreteHandler)
具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家
由于处理者持有下家引用,因此,如果需要,具体处理者可以访问下家
关联模式
外观模式
在设置责任链中的链条时,可能会用到外观模式,让客户端应用只与外观打交道
组合模式
也是一种树形结构,只不过它只有一条主干而已,没有其他分支,因此可以说在责任链中应用了组合模式配置链条
命令模式
涉及了请求传递的行为,请求的传递就用到了命令模式
观察者模式
一种广播形式,主要是事件触发,将消息发送出去,信息接收者可以同时存在多个
而责任链模式是按照既定规则进行一系列的消息处理,并且只有一个接收者接收消息并进行传递
使用场合
有多个对象处理同一个请求,具体由哪一个来处理还不确定,只有在运行时才能确定哪个对象处理的情况
消息具有多个接收者,而接收对象又是不明确的情况
只需要向其中的一个对象发出消息,由其内部具体处理
同一个消息的多个处理对象可能会动态增加或者减少,需要动态地指定的情况
命令模式
定义
命令模式将一个请求封装为一个对象,从而使用户可用不同的请求对客户进行参数化
将请求排队或记录请求日志,支持可撤销的操作,命令模式的根本目的在于将“请求者”与“实现者”之间解耦
设计原则
“开-闭”原则
命令模式如果新增加一个具体的命令,不必修改请求的调用者,调用者就能使用具体命令,发送请求
如果新增加一个请求调用者,也不必修改具体的命令和命令接收者,新增的调用者就会使用已有的具体命令
最少知识原则
在命令模式中,请求的启动者发送命令请求给具体命令,由具体命令负责发送命令消息给命令的接收者
模式中的角色
抽象命令角色(Command)
声明命令执行操作的接口,由java接口或者抽象类来实现
具体命令角色(Concrete Command)
在具体的命令角色中绑定命令接收者,命令调用接收者做出相应的操作,从而实现命令角色声明的执行操作的接口行为
请求者角色(Invoker)
命令的启动者角色,调用命令对象执行请求
接收者角色(Receiver)
具体命令执行时的行为对象,任何类都可能作为一个接收者
客户角色(Client)
创建一个具体命令对象,并分配命令的接收者
关联模式
组合模式:在使用宏命令时,我们会用到组合模式
备忘录模式:可以用来存储命令的效果状态信息,用于命令的撤销和恢复功能
原型模式:可以使用原型模式(实现Cloneable接口)来复制命令
使用场合
抽象出待执行的动作以参数化某对象
类似于过程设计中的回调机制,而命令模式正是回调机制的一个面向对象的替代品
在不同的时刻指定、排列和执行请求
需要支持可撤销的操作
需要支持修改日志功能。这样当系统崩溃时,这些修改可以被重做一遍
需要支持事务系统
解释器模式
定义
解释器模式就是给定一个语言的文法表示,并且定义一个解释器,用来解释语言中的句子
设计原则
“开-闭”原则
增加新的非终结符类就可实现增加新的语法规则,对于原有系统语法规则不会产生任何影响
封装变化部分
将变化的部分封装在非终结符表达式中,这使得修改语法规则和增加语法规则只需针对非终结符进行,而不必修改终结符表达式内容
模式中的角色
抽象表达式角色(AbstractExpression)
声明一个所有的具体表达式角色都要实现的抽象接口
这个接口主要是一个interpret()方法,称做解释操作
终结符表达式角色(Terminal Expression)
这是一个具体角色,实现了抽象表达式角色所要求的接口
主要是一个interpret()方法,方法中的每一个终结符都有一个具体终结表达式类与之相对应
非终结符表达式角色(Nonterminal Expression)
这是一个具体角色。文法中的每一条规则R=R1R2...Rn都需要一个具体的非终结符表达式类,对于每一个R1R2...Rn中的符号都持有一个类型为AbstractExpression的实例变量
此角色同样要实现解释操作,即interpret()文法,解释操作以递归方式调用上面所提到的代表R1R2...Rn的各个符号的实例变量
上下文环境角色(Context)
提供解释器之外的一些全局信息,比如变量的真实值等
客户端角色(Client)
代表模式的客户端有以下功能——建造一个抽象语法树;调用解释操作interpret()
关联模式
组合模式
从解释器模式的静态类图中可以看到,在非终结符表达式角色中含有对抽象表达式角色的引用,应用了组合设计模式,形成递归的调用结构
享元模式
在解释器模式中有终结符表达式角色,这个角色在实际当中一般是可共享的数据,因此可以应用享元设计模式共享数据
访问者模式
在语法规则中的各个节点进行访问操作时,可能会用到访问者模式进行处理
使用场合
一种特定类型的问题发生的频率足够高,并且业务规则频繁变化,不断重复出现类似情况
业务规则不是过于复杂烦琐,比较容易抽象出语法规则
效率不是软件系统中主要考虑的因素
迭代器模式
定义
提供了一种模式顺序访问一个集合对象中的各个元素功能,而又不暴露其内部的表示
设计原则
“开-闭”原则:迭代器实现对原系统不产生任何影响
单一职责原则
集合对象和迭代器之间分工明确,职责单一,迭代器的应用解除了外部应用和集合对象之间的耦合,使软件结构更加灵活、易于扩展
模式中的角色
迭代器角色(Iterator)
迭代器角色负责定义访问和遍历元素的接口
迭代器的抽象是为了使迭代器不依赖于容器的内部结构
具体迭代器角色(Concrete Iterator)
具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置
容器角色(Container)
容器角色负责提供创建迭代器角色的接口
具体容器角色(Concrete Container)
具体容器角色实现创建具体迭代器角色的接口,这个具体迭代器角色与该具体容器的内部结构相关
关联模式
组合模式
组合模式是一种递归结构的设计模式,而迭代器模式是针对集合类对象的遍历结构,两者是存在区别的,不能混淆
访问者模式
迭代器模式是遍历集合对象中的各个元素,迭代器只是遍历集合对象,获取元素内容,并没有做任何处理上的实现
而访问者模式则是穿梭于各个元素对象之间,并且不断地重复同一处理的设计模式
工厂方法模式
在集合对象生成迭代器的时候,我们会用到工厂方法模式,让子类来决定创建哪一种具体的迭代器
使用场合
访问一个集合对象的内容,而无须暴露它的内部表示
支持对集合对象的多种遍历方式
为遍历不同的集合对象结构提供一个统一的接口
中介者模式
定义
用一个中介对象来封装一系列对象之间的交互,使各个对象中不需要显式地引用其他对象实例
从而降低各个对象之间的耦合度,并且可以独立地改变对象间的交互关系
设计原则
一对多的对象依赖转化为一对一依赖
集中控制提高类的复用性
模式中的角色
抽象中介者角色(Mediator)
抽象中介者角色定义了统一的接口与各个同事角色之间进行通信
具体中介者角色(ConcreteMediator)
具体中介者角色实现抽象中介者接口,具体协调各个同事类之间的协作
抽象同事角色(Colleague):定义与中介者之间沟通的接口
具体同事角色(Concrete Colleague)
实现抽象同事角色接口,具体处理与中介者的通信行为
关联模式
外观模式
在外观模式中,外观角色是构成系统内部复杂子系统的单一窗口,对系统外部提供更高一级的接口API
而中介者模式中的中介者角色则充当着各个同事对象间信息交互的中间角色。外观模式是单向的信息传达,而中介者则是双向的信息通信
观察者模式
在中介者模式中,中介者参与同事角色之间的通信方式,使用的是观察者模式
使用场合
一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解。注意是多个对象之间相互依赖
在中介者模式中,中介者参与同事角色之间的通信方式,使用的是观察者模式
想定制一个分布在多个类中的行为,而不想生成太多的子类的场合
产品架构的研发,更需要易于扩展的场合
备忘录模式
定义
备忘录模式是在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
这样以后就可将该对象恢复到原先保存的状态
设计原则
封装边界的保持
双重接口实现,保证安全性
模式中的角色
发起人角色(Originator)
发起人角色在要存储当前状态时,产生一个备忘录
在需要恢复之前的状态时,则接收外部备忘录对象用来恢复状态
备忘录角色(Memento)
备忘录角色用来保存某一时刻发起者对象的内部状态信息,但是需要保证不能将其保存的信息泄露给其他对象
该角色包含两种接口:宽接口(只能被发起者访问的接口)和窄接口(给外部对象使用的接口)
管理者角色(Caretaker)
管理者角色用来保存发起者对象产生的备忘录实例,然后在一个合适的时机,发起者通知管理者,获得备忘录对象实例恢复之前的状态
关联模式
命令模式
在讲解命令模式的时候,我们曾经提到利用中间的命令角色可以实现撤销和重做的功能
而备忘录模式则是用来存储对象历史状态信息的,因此在命令模式中可使用备忘录模式实现撤销和重做的功能
原型模式
在原型模式中,使用克隆的方式将对象的所有信息都复制一份,而备忘录模式则是存储那些需要还原的状态信息
状态模式
在后面将要讲解的状态模式中,使用类来描述程序中的各种状态,而备忘录模式则是使用对象实例表示的状态信息
使用场合
需要在某一时刻恢复一个对象先前的状态时
需要在外部保存对象某一时刻的状态,但如果用一个接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性
观察者模式
定义
观察者模式又称为发布/订阅模式,它是软件设计模式中的一种
观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
设计原则
“开-闭”原则:可以在运行时动态增加观察者对象
单一职责原则:每一个观察者处理自身的更新行为,功能职责单一
依赖倒置原则:具体主题对象中存储的是观察者接口类型,有利于观察者对象的变化(增加或者删除),系统更加灵活、更易扩展
模式中的角色
抽象主题角色(Subject)
定义被观察者接口,包括注册观察者方法(将观察者添加到集合容器中)、注销观察者方法,以及当发生变化时通知更新观察者方法
具体主题角色(ConcreteSubject)
定义了具体的被观察对象,在其内容中含有存储观察者对象实例的集合,用于保存注册的观察者对象
抽象观察者角色(Observer)
定义观察者通用接口,通常包含一个update接口方法,用于在被观察者发生变化时,调用该方法更新数据
具体观察者角色(ConcreteObserver)
定义具体的观察者对象,实现update更新方法,与具体主题角色状态一致
中介者模式
在中介者模式中,中介者参与同事角色之间的通信方式,使用的是观察者模式
然而,中介者模式和观察者模式存在一定的区别
在中介者模式中,通知状态变化只是模式中的一部分,该模式的重点是协调各个同事类之间的协作
而观察者模式的侧重点在于,当主题发生变化时,观察者获得通知而与主题状态同步
使用场合
当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,需要将这两个方面分别封装到独立的对象中,彼此独立地改变和复用的时候
当一个系统中一个对象的改变需要同时改变其他对象内容,但是又不知道待改变的对象到底有多少个的时候
当一个对象的改变必须通知其他对象做出相应的变化,但是不能确定通知的对象是谁的时候
状态模式
定义:一个对象的内在状态改变时允许改变其行为,这个对象看起来就像是改变了其类
设计原则
“开-闭”原则:新增状态易如反掌,不会影响其他状态对象
单一职责原则:每一个状态类专注实现与自身状态相关的功能,职责功能单一
模式中的角色
抽象状态角色(State)
抽象状态角色定义不同状态下的不同处理接口
这个接口是所有不同状态所作处理方法集合
具体状态角色(ConcreteState)
具体状态角色表示不同的处理状态,实现抽象状态中的相关接口方法
上下文环境角色(Context)
保存当前状态信息,同时还定义了状态模式使用者的接口方法,在方法中使用当前状态实现相关的行为
关联模式
单例模式
状态模式中的具体状态一般被实现成单例模式,从而减少系统因创建状态对象所消耗的时间
享元模式
在一些情况下,会使用享元模式让上下文环境共享具体的状态实例对象
策略模式
状态模式和策略模式很相似,都是利用多态把一些操作分配到一组相关的简单的类中
但是两种模式是存在区别的,状态模式主要解决的是复杂逻辑处理的状态迁移,而这个过程是由对象的内部条件决定的,外界只需关心其接口,不必关心状态对象的创建和转化
策略模式则是一组方案或者说是算法的相互替换,策略模式用于随不同外部环境采取不同行为的场合,采取何种策略由外部条件决定
使用场合
一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变其行为
一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态
策略模式
定义:定义一系列的算法,将每一种算法封装起来并可以相互替换使用,策略模式让算法独立于使用它的客户应用而独立变化
设计原则
“开-闭”原则
新增一种具体策略只要实现抽象策略即可,对于原有系统的稳定性不构成影响
单一职责原则
每一个具体策略类功能职责单一,专注于实现自身的策略行为
模式中的角色
抽象策略角色(Strategy)
抽象策略角色通常由一个接口或者抽象类实现,定义公共的策略方法
具体策略角色(ConcreteStrategy)
具体策略角色实现具体的策略算法,包装相关的算法和行为
上下文环境角色(Context)
上下文环境角色中含有一个对具体策略对象实例的引用,最终供客户端应用程序调用
关联模式
抽象工厂模式
在抽象工厂模式中,可以切换具体的工厂或者产品,而在策略模式中实现的是切换策略算法
状态模式
状态模式与策略模式都是采用对象组合的方式,都是利用多态把一些操作分配到一组相关的简单的类中
两者的区别在于两种模式所表示的内容是不同的,状态模式是切换状态,当状态发生改变时,一定会切换委托对象的类实例
而策略模式切换的是算法,算法的相互替换是外部环境根据具体情况进行的切换,是由外部条件决定的
模板方法模式
在后面将要讲解的模板方法模式在某些场合中与策略模式存在一定的争议
举例:当策略模式中的具体策略不能确定时,需要我们根据系统实际情况自己实现具体策略,这时两种模式可以说都是满足要求的
模板方法模式就是让子类实现某些功能,而此时实现的正是具体策略子类,因此两者存在着争议
使用场合
当多个类的表现行为不同,需要在运行时动态选择具体要执行的行为的时候
需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其他方式实现的时候
需要隐藏具体策略(算法)的实现细节,各个具体策略(算法)彼此独立的时候
当一个类中出现了多种行为,而且在一个操作中使用多个条件分支来判断使用多种行为的时候,可以使用策略模式将各个条件分支的动作植入具体策略中实现
模板方法模式
定义
定义一个操作中的算法骨架,而将一些实现步骤延迟到子类当中
模板方法模式使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤
设计原则
“开-闭”原则
模板方法模式使用抽象父类控制顶级逻辑,把某些基本操作的实现推迟到子类去实现,这是通过继承的手段来达到对象复用的目的,不同的子类实现不同的具体功能,遵守了“开-闭”原则
好莱坞原则
允许低层组件将自己挂钩到高层组件的算法过程中,什么时候去调用,则按照高层的处理逻辑决定。有效避免了系统环状依赖
模式中的角色
抽象参与者(AbstractClass)
在抽象参与者中,声明了模板方法,在模板方法中实现业务处理逻辑
其中尚未实现的抽象方法由子类实现
具体参与者(ConcreteClass)
关联模式
工厂方法模式
工厂方法模式是模板方法模式的特殊情况,工厂方法模式中使用子类来产生对象实例
策略模式
策略模式中使用委托关系切换整个算法,不是部分修改算法内容,整个算法结构已经改变了
而模板方法模式则是使用继承的方式,让子类实现部分的算法内容,从而实现整个算法处理,但是算法骨架仍然是由抽象基类决定的
使用场合
一次性实现一个算法不变的部分,并将可变的行为留给子类来实现
各子类中具有公共行为的时候,应被提取出来并集中到一个公共父类中以避免代码重复
当需要控制子类扩展的时候。模板方法在特定点调用钩子操作,这样就只允许在这些点进行扩展
访问者模式
定义
访问者模式是表示一个作用于某对象结构中的各元素的操作
它使用户可以在不改变各元素类的前提下定义作用于这些元素的新操作
设计原则
“开-闭”原则
访问者模式将处理功能逻辑从数据结构中分离出来,这就使得增加或者修改功能变得简单
我们只要新增或者修改访问者角色即可达到目的,而不必修改数据结构,保证了原有系统的稳定性,实现了对系统的扩展
单一职责原则
数据结构角色和访问者角色之间的职责分工明确,访问者角色主要负责进行数据的复杂处理逻辑,维持以数据结构角色为基础的处理行为
各个访问者之间的职责功能单一,各个访问者角色实现各自的处理逻辑行为,实现特定的功能
模式中的角色
抽象访问者角色(Visitor)
为该对象结构中的具体元素角色声明一个访问操作接口
在该接口中为对象结构中的每一个具体元素声明一个访问接口方法,这样访问者就可以通过该元素角色的特定接口直接访问它
具体访问者角色(ConcreteVisitor.)
实现抽象访问者角色声明的接口,实现具体的功能
抽象元素角色(Element)
该角色是一个访问者的接收者,定义一个接收访问者抽象接口方法accept(),它以一个访问者接口Visitor作为参数传入
具体元素角色(ConcreteElement):实现抽象元素Element中所定义的接收访问者接口
结构对象角色(ObjectStructure)
这是使用访问者模式必备的角色
它具备以下特性:能枚举它的元素
可以提供一个高层接口以允许访问者访问它的元素;若有需要,可以设计成一个复合对象或者一个聚集(如一个列表或无序集合)
关联模式
迭代器模式
迭代器模式和访问者模式都是在结构对象上进行处理操作
不同的是,迭代器模式主要用于获取结构对象的每一个元素,而访问者模式则是对结构对象中的每一个元素做特殊的处理
组合模式
本章使用的就是之前组合模式中的示例内容
正如本章示例内容所示,访问者访问的结构对象就是组合模式结构
解释器模式
在解释器模式中,也存在结构对象遍历的行为
因此在解释器模式中可以应用访问者模式在各个节点之间穿梭,从而完成树形结构的解析过程
使用场合
如果在一个对象结构中包含很多不同类型对象,它们有不同的接口,而想对这些不同对象实施一些依赖于其具体类的操作
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而想避免让这些操作与这些对象的类关联起来
访问者模式使得可以将相关的操作集中起来,单独定义在一个类中
当该对象结构被很多应用共享时,用访问者模式让每个应用仅包含需要用到的操作
定义对象结构的类很少改变,但经常需要在此结构上定义新的操作
书籍信息
作者: 郑阿奇
出版社: 电子工业出版社
出版年: 2011-11
相关书籍推荐
《认知迭代》
《AI·未来》
《知识大迁移》
一、关于设计模式
面向对象的三大特性
封装
把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的类进行信息隐藏
继承
可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展
但是基类的构造函数、复制构造函数、析构函数、赋值运算符不能被派生类继承
多态
一个类实例的相同方法在不同情形有不同表现形式
多态实现的两种方式:将子类对象的指针赋给父类类型的指针或将一个基类的引用指向它的派生类实例
软件设计原则
高内聚、低耦合
所谓高内聚,是指一个软件模块内各个元素彼此结合的紧密程度要高,即一个软件模块是由相关性很强的代码组成,只负责一项任务,也就是常说的单一责任原则
所谓低耦合,是指一个软件结构内不同模块之间的互连程度要低
模块间耦合的高低取决于模块间接口的复杂性、调用的方式及传递的信息
开-闭”原则:对扩展开放,对修改关闭
面向抽象编程
程序都依赖于抽象,而不是依赖具体实现
多用组合少用继承
设计模式(Design Pattern)
就是一套被反复使用、多数人知晓的、经过分类编目的代码设计经验的总结,是一种解决问题的思想
学习设计模式,掌握设计模式的实现要点,最重要的是在学习设计模式当中掌握软件设计原则
设计模式可以分为类模式和对象模式
类模式用来处理类和子类之间的关系,这些关系通过继承建立,是静态的,在编译时刻便确定下来了
对象模式是处理对象间的关系,这些关系在运行时是可以变化的,更具动态性
按照目的来分,设计模式可以分为创建型模式、结构型模式和行为型模式
创建型模式用来处理对象的创建过程
结构型模式用来处理类或者对象的组合
行为型模式用来对类或对象怎样交互和怎样分配职责进行描述
设计模式总结
开-闭”原则(OCP)
个软件实体应当对扩展开放,对修改关闭
单一职责原则(SRP)
一个类,应该只有一个引起它变化的原因
依赖倒置原则(DIP)
要依赖于抽象,而不要依赖于具体实现
依赖倒置原则是实现“开-闭”原则的重要途径
接口隔离原则(ISP)
使用多个隔离的接口,分离不同的接口行为,也就是说一个类对另外类的依赖性应当建立在最小接口上
是对“开-闭”原则的补充,讲的是基类和子类的关系
里氏替换原则(LSP)
该原则是对“开-闭”原则的补充,讲的是基类和子类的关系
迪米特法则(LoD)
又称为最少知识原则
和密友交谈
即一个软件实体应当尽可能少地与其他实体发生相互作用
二、创建型模式
工厂方法模式
定义:一个创建产品对象的工厂接口,让子类决定实例化哪一种实例对象
通过继承的方式实现应用程序的解耦,让子类决定实例化哪一个具体类型
设计原则
“开-闭”原则
依赖倒置原则
不论工厂还是产品都应该依赖于抽象,而不是具体的实现类
使用场合
当子类型可能会有很多,以后需要不断增添不同的子类实现时
当一个系统尚在框架设计阶段,还不知道将来需要实例化哪些具体类时
系统设计之初不需要具体对象的概念(或者说没有具体对象的概念)
抽象工厂模式
定义:提供一个接口,用于创建相关或者依赖对象的家族,而不需要指定具体的实现类
设计原则
“开-闭”原则
多用对象组合,少用继承(不是不用)
针对抽象编程,不针对实现编程
产品对象通过抽象工厂暴露的方法创建,具体工厂创建具体产品
关联模式
抽象工厂模式和工厂方法模式的区别
工厂方法模式通过继承的方式实现应用程序的解耦,而抽象工厂模式则通过对象组合的方式实现应用程序的解耦
工厂方法模式用来创建一个抽象产品,具体工厂实现工厂方法来创建具体产品,而抽象工厂模式用来创建一个产品家族的抽象类型
使用场合
创建产品家族,相关产品集合在一起使用的时候
想要提供一个产品类库,并只想显示其接口而不是实现时
通过组合的方式使用工厂时
建造者模式
定义:将复杂对象的创建与表示分离,使得同样的构建过程可以创建不同的表示
关联模式
建造者模式和抽象工厂模式的区别
建造者模式着重于分步骤构造一个复杂对象,而抽象工厂模式则着重于多个系列的产品对象即对象族(简单的或复杂的)的构造
建造者模式是在最后一步返回具体产品,而抽象工厂模式则是立即返回具体产品
设计原则
分步骤创建复杂对象,使构建复杂对象变得不那么复杂
构建和表示分离,更好地适应外部需求的变化
单一职责原则,提高软件内部的聚合度,降低模块之间的耦合度
使用场合
当生成的产品对象内部具有复杂的结构时
当复杂对象需要与表示分离,可能需要创建不同的表示时
当需要向客户隐藏产品内部结构的表现时
原型模式
定义:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象
注意事项
克隆对象时,原始对象的构造方法不被执行
浅复制:浅复制只是复制本对象的原始数据类型
举例如int、float、String等,对于数组和对象引用等是不会复制的
因此,浅复制是有风险的
深复制:不但对原始数据类型做复制,对于对象中的数组和对象引用也做复制的行为,从而达到将对象完全复制的效果
设计原则
考虑产生对象的复杂度和类复用
结合系统结构考虑使用浅复制还是深复制
使用场合
产生对象过程比较复杂,初始化需要许多资源时
希望框架原型和产生对象分开时
同一个对象可能会供其他调用者同时调用访问时
单例模式
定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
使用场合
当在系统中某个特定的类对象实例只需要有一个的时候,可以使用单例设计模式
需要注意的是,只有真正有“单一实例”的需求时才可使用
多例模式的实现原理
首先,在类中设置一个存储多个实例的容器,如ArrayList或HashMap
然后,静态初始化实例对象并添加到容器中;最后,根据条件返回容器中的实例对象
用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象
三、结构型模式
对象适配器模式
定义:把一个类的接口转换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作
设计原则
使用对象组合,面向接口和抽象编程
“开-闭”原则
关联模式
与桥接模式和装饰者模式的区别
与桥接模式的区别
适配器模式是将一种接口转换为另外一种接口的设计模式,而桥接模式则是把实现和它的接口分开,以便它们可以独立地变化
桥接模式并不是用来把一个已有的对象接到不相匹配的接口上的
与装饰者模式的区别
适配器模式主要用来填补两个接口之间的差异,而装饰者模式则是不需要更改接口,就可以新增功能的设计模式
使用场合
软件系统结构需要升级或扩展,又不想影响原有系统的稳定运行的时候
转换类之间的差别不是太大的时候
想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作的时候
桥接模式
定义:在软件系统中,某些类型由于自身的逻辑,具有两个或多个维度的变化,如何应对这种“多维度的变化”
桥接模式使得软件系统能够轻松地沿着多个方向变化,而又不引入额外的复杂度
桥接模式的用意是“将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化”
设计原则
使用聚合关联,不使用继承关联
抽象化层次和实现化层次脱耦
关联设计模式
抽象工厂模式:有时,为了使设计更加抽象化,在桥接模式中会使用抽象工厂模式
适配器模式
在上一章,我们已经了解到适配器模式与桥接模式的区别,适配器模式是将一种接口转换为另外一种接口的设计模式
而桥接模式则是要把实现和它的接口分开,以便它们可以独立地变化
模板方法模式:利用实现的类层次,在父类中定义抽象方法,然后在子类中实现抽象方法
使用场合
不希望在抽象类和它的实现部分之间有一个固定的绑定关系
类的抽象及实现都应该可以通过生成子类的方法加以扩充
对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译
组合模式
定义
将对象组合成树形结构以表示“部分-整体”的层次结构就是组合模式
组合模式使得用户对单个对象和组合对象的使用具有一致性
组合模式模糊了简单元素和复杂元素的概念,使客户程序可以像处理简单元素一样来处理复杂元素,从而使客户程序与复杂元素的内部结构解耦
设计原则
统一对待个别对象和组合对象
面向抽象编程
关联模式
命令模式:在使用命令模式,建立宏命令时会用到组合模式
装饰者模式
组合模式是对单个对象和组合对象使用一致性,一视同仁
装饰者模式则是对装饰者和被装饰内容使用一致性
使用场合
想表示对象的“部分-整体”层次结构的时候
希望用户忽略组合对象与单个对象的不同,用户将统一使用组合结构中的所有对象的时候
装饰者模式
定义
装饰者模式是在不改变原类文件和使用继承的情况下,动态地扩展一个对象的功能
它是通过创建一个包装对象,也就是装饰来包裹真实的对象
设计原则
封装变化部分
装饰者模式应用中“变化”的部分是组件的扩展功能,装饰者和被装饰者完全隔离开来
这样就可以任意改变装饰者和被装饰者,而不会产生任何影响
对扩展开放,对修改关闭
装饰者模式动态地对组件进行扩展,增添新的功能,这完全是增量修改,对原有的软件功能结构没有任何影响
面向抽象编程,不要面向实现编程
在装饰者模式中,装饰者角色就是抽象类实现,面向抽象编程的好处就在于起到了很好的接口隔离作用
在运行时,具体操作的也是抽象类型引用,这些都显示了面向抽象编程
优先使用对象组合,而非类继承
装饰者模式最成功的地方就是合理地使用了对象组合方式,通过组合灵活地扩展了组件的功能
所有的扩展功能都是通过组合而非继承获得的,这从根本上决定了这种实现是高内聚、低耦合的
模式中的角色
被装饰者抽象Component
是一个接口或抽象类,就是定义最核心的对象,也是最原始的对象
这个类是我们需要装饰类的基类
被装饰者具体实现ConcreteComponent
这是Component类的一个实现类,我们要装饰的就是这个具体的实现类
装饰者Decorator
一般是一个抽象类,实现接口或者抽象方法,它里面必然有一个指向Component变量的引用
装饰者实现ConcreteDecorator
是具体的装饰者类,用来装饰最基本的类
关联模式
适配器模式
装饰者模式是在不改变原内容的基础上,动态地增加新的行为
而适配器模式则主要用来填补两个接口之间的差异,将一个接口转化为另一个接口
策略模式:策略模式是以切换运算法则的方式变换功能的
使用场合
当我们需要为某个现有的对象动态地增加一个新的功能或职责时,可以考虑使用装饰模式
当某个对象的职责经常发生变化或者经常需要动态地增加职责,避免为了适应这样的变化而增加继承子类扩展的方式
因为这种方式会造成子类膨胀的速度过快,难以控制,此时可以使用装饰者模式
外观模式
定义
外观模式为子系统中的一组接口提供一个统一的高层接口,使子系统更容易使用
外观模式通过一个外观接口读/写子系统中各接口的数据资源,而客户可以通过外观接口读取内部资源库,不与子系统产生交互
设计原则
迪米特法则——最少知识原则
一个软件实体应当尽可能少地与其他实体发生相互作用,即“只和你的密友谈话”
封装变化部分:将系统中可能发生变化的部分独立出来,进行封装
这对外部应用是完全透明的,外部应用根本感觉不到内部发生的变化
模式中的角色
外观角色(Facade)
构成系统内部复杂子系统的单一窗口,对系统外部提供更高一级的接口API
子系统角色
系统内部各种子系统各司其职,做好“本职工作”
外观角色的存在对它们并不产生任何影响,它们听从外观角色的调用,但不会反过来调用外观角色
客户端角色
作为外部应用的客户端角色,不关心系统内部复杂子系统的运作情况,而只与外观角色之间通信获得数据和结果
关联模式
抽象工厂模式
抽象工厂模式可以理解为与产生复杂对象有关的外观模式,因为在抽象工厂模式中提供更高一级的调用接口API,供外部应用调用获得对象实例
单例模式
外观模式与单例模式联系得比较紧密,因为一般情况下,外观模式经常被设计为单例模式运作,供外部应用调用
中介者模式
中介者模式扮演系统中各个参与者的中间人,封装各个参与者之间的交互,中介者模式使得系统中各个对象之间不需要显式地相互调用,从而使系统的各个参与者相互解耦
外观模式是外观单方面调用其他参与者形成更高一级的接口,供外部应用调用
使用场合
一个软件系统的复杂度比较高,需要一个更高级别的简单接口简化对子系统的操作时
当使用端与实现类之间有太多的相依性,需要降低使用端与子系统或子系统间的耦合性,增加子系统的独立性时
当子系统是相互依存的,需要层级化子系统,简化子系统之间的相依性的时候,可以使用外观模式
享元模式
定义
享元模式以共享的方式高效地支持大量的细粒度对象
通过复用内存中已存在的对象,降低系统创建对象实例的性能消耗
设计原则
共享细粒度对象,降低内存空间
有效地隔离系统中的变化部分和不变部分
模式中的角色
抽象享元角色
此角色是所有具体享元类的超类,为这些类规定出需要实现的公共接口
那些需要外蕴状态(External State)的操作可以通过调用商业方法以参数形式传入
具体享元角色
实现抽象享元角色所规定的接口。如果有内蕴状态,则必须负责为内蕴状态提供存储空间
享元对象的内蕴状态必须与对象所处的周围环境无关,从而使享元对象可以在系统内共享
享元工厂角色
本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享
当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个符合要求的享元对象
如果已经有了,享元工厂角色就提供这个已有的享元对象;如果系统中没有适当的享元对象,享元工厂角色就创建一个合适的享元对象
客户端角色
本角色需要维护一个对所有享元对象的引用
本角色需要自行存储所有享元对象的外蕴状态
关联模式
组合模式:可以使用享元模式共享组合模式中的叶子节点,从而提高系统的处理效率
单例模式
在享元模式中,一般都是将享元工程设置为单例模式,以降低系统使用空间
除此之外,单例模式本身就是一种享元模式!单例模式只有一个对象实例,被其他对象所共享
使用场合
当系统中某个对象类型的实例较多的时候
在系统设计中,对象实例进行分类后,发现真正有区别的分类很少的时候
代理模式
定义
两个对象参与处理同一请求,接收的请求由代理对象委托给真实对象处理,代理对象控制请求的访问,它在客户端应用程序与真实目标对象之间起到一个中介桥梁的作用
设计原则
延迟加载,提高系统效率
单一职责原则
模式中的角色
抽象角色(IRealObject):声明真实对象和代理对象的共同接口
真实角色(RealObject):真正处理请求的目标对象
代理角色(Proxy)
代理对象角色内部含有真实对象的引用,从而代理对象可以将请求转为真实对象处理
同时,代理对象在执行真实对象操作的前后还可以添加附加操作
关联模式
装饰者模式:装饰者模式重点在于添加附加行为修饰被装饰者
而代理模式的重点则是代替本人作业,减少对实际对象的操作
使用场合
远程代理(RemoteProxy)为一个对象在不同的地址空间提供局部代理
虚拟代理(VirtualProxy)中
若一个对象的创建非常耗时,可通过代理对象去调用,在真实对象创建前,返回一个假的调用
等真实对象创建好了,这时返回给客户端的就是一个真实对象的相应方法调用
保护代理(ProtectionProxy)控制对原始对象的访问
智能指引(SmartReference)取代了简单的指针,它在访问对象时执行一些附加操作