适配器模式、命令模式与模板方法模式
A.适配器模式
a.适配器模式将一个接口转换为另外的接口。
b.名称的由来:
1.adapter很像变压器,变压器把一种电压变换成为另外一种电压。比如把220v电压转换成为5v电压,这是我们很多充电器要使用的方式。Adapter在中文中也可以翻译成为转换器,适配器。
2.同时这种做法也很像货物的包装过程:被包装的货物的真实样子被包装所掩盖和改变。因此有人把这种模式也叫做包装模式(wrapper).事实上,大家经常写很多这样的wrapper类,把已有的一些类包装起来,使之能有满足需要的接口。
c.适配器模式分成:
类的适配器模式和对象适配器模式:
public interface Target{
sampleMethod1();
sampleMethod2();
}
public class Adaptee{
sampleMethod1();
}
可以看出,Adaptee类没有sampleMethod2()方法,而客户端则期待这个方法。为使得客户端能够使用这个Adaptee类,提供一个中间环节,即类Adapter,把Adaptee的Api与Target类的API衔接起来。Adapter和Adaptee类是继承关系。这决定了这个适配器模式是类的。
public class Adapterextends Adaptee implements Target{}
d.模式所涉及的角色:
1.目标角色(target):这就是所期待得到的接口。注意这里是类适配器模式,因此目标不可以是类。
2.源角色(Adaptee):现在需要适配转换的接口
3.适配器角色(Adapter):适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。
publicinterface Target{
public void sampleMethod1();
public void sampleMethod2();
}
Public class Adaptee{
publicvoid sampleMethod1();
}
Public class Adapter implements Target{
Adapteeadaptee;
publicAdapter(Adaptee adaptee){
this.adaptee = adaptee
}
publicvoid sampleMethod1(){
this.adaptee.sampleMethed1();
}
publicvoid sampleMethod2(){
//
}
}
e.对象的适配器模式:
Adaptee类没有sampleMethod2()方法,而客户端则期待这个方法,为使得客户端能够使用这个Adaptee类,需要提供一个包装wrapper类Adapter。这个包装类包装一个Adaptee的实例。从而这个包装类能够把Adaptee的API和Target类的API衔接起来。而Adapter与Adaptee是委派关系,因此这种模式是基于对象的。
f.定义:
1.将一个接口转换成为另外一个接口,以符合客户的使用要求。
2.或者将两个不兼容的类纠合在一起使用,让客户从实现的接口中解耦。
g.使用场景(什么时候使用?):
1.两个类所做到事情相同或者相似,但是具有不同的接口的时候,和客户要求不符合的时候。
2.旧的系统开发的类已经实现了一些功能,但是客户端却只能以另外接口的形式访问,但是我不希望手动更改原有的类;
3.使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己定义的接口,但是要使用第三方组件接口的功能。
通常在软件设计的后期或者维护期才考虑使用。不同产品,不同开发人员,不同厂家设计造成功能相似但是接口不同的情况。
因此,应当事先预防接口不一致的问题,不匹配的问题就不会发生。
而适配器模式解决的恰恰是接口发生了变化导致现有对象不能工作的情景,通过组合这个现有对象,将现有接口转化为目标接口的。应该说,使用适配器模式是不得已而为之的一种方式
h.体现的OO设计原则:
1.对象组合,而不是继承(对象适配器),这样设计更有弹性(使用组合将工作委托给被适配者)。不仅可以适配一个类,也可以适配该类的子类。
i.与其他模式的比较:
1.装饰模式强调的是通过组合来动态扩展对象功能。是适配器模式的变种,不改变接口。代理模式强调的是控制对其他对象访问,也没有改变接口。适配器模式只是简单的接口转换。并没有扩展行为。
j.适配器结构图
B.命令模式
命令模式是对命令的封装
命名模式把发出命令的责任和执行命令的责任分割开来,委派给不同的对象。
每个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行,何时被执行,以及怎么被执行的。
a.命令模式涉及的角色:
1.客户角色:创建了一个具体的命令(ConcreteCommand)对象并确定其接收者。
2.命令角色com mand:声明了一个给所有具体命令类的抽象接口。这是一个抽象角色。通常由一个java接口或者java抽象类实现。
3.具体命令(ConcreteCommand)角色:定义一个接受者和行为之间的弱耦合;实现execute()方法。负责调用接受者的相应操作。Execute()方法通常叫做执行方法。
4.请求者(invoker)角色:负责调用命令对象执行请求。相关的方法叫做行动方法。
5.接收者角色(Receiver):负责具体实施和执行一个请求。任何一个类都可以成为一个接收者,实施和执行请求的方法叫做行动方法。
b.命令模式结构图
c.怎样解耦?
1.将动作(请求)封装为命令对象,包含两个部分: 由谁来做?做什么?
2.有多少个动作就封装多少个命令对象;可以动态的添加或者删除命令对象。
3.引入中介者对象invoker :记录命令,传递命令执行。
C.模板方法模式
a.模板方法模式封装算法(或业务流程);子类实现特定的步骤。
b.定义
c.模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤.算法的结构: 根据需求设计出来的业务流程
d.特定的步骤: 在内容上存在变化的部分. 模式中抽象方法
e.涉及的角色:
1.AbstractClass(抽象类):定义了一到多个的抽象方法,以供具体的子类来实现它们;而且还要实现一个模板方法,来定义一个算法的骨架。该模板方法不仅调用前面的抽象方法,也可以调用其他的操作,只要能完成自身的使命
2.ConcreteClass(具体类):实现父类中的抽象方法以完成算法中与特定子类相关的步骤
f.特点:
1.模板方法模式通过把不变的行为转移到超类,去除子类中重复的代码. 提供了很好的代码复用平台.
2.使用模板方法使系统扩展性增强,最小化了变化对系统的影响
g.适用环境:
1.具有统一的操作步骤或操作过程
2.具有不同的操作细节
3.存在多个具有同样操作步骤的应用场景,但某些具体的操作细节却各不相同
h.模板方法模式---Factory方法模式
1.相同点: 在抽象类中定义抽象方法 ,通过子类继承,重载父类的的抽象方法实现.
2.不同点:
²Template方法模式只有继承关系, Factory方法模式除了继承外,还有创建的过程.
²Factory方法模式中,被定义的抽象方法创建了抽象产品。工厂类和产品类之间存在创建和被创建的关系。而Template方法模式不存在产品关系。
²工厂方法模式是模板方法的一个特殊版本
3.好莱坞原则:
²“别调用我们,我们会调用你”。高层组件对待底层组件的方式是: 别调用我们,我们会调用你!
4.通过钩子来实现好莱坞原则:
²允许底层组件将自己挂钩到系统上,但是高层组件会决定什么时候或怎样使用这些底层组件。
D.职责链模式
多个对象都有机会处理请求, 从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求, 知道一个对象处理它为止.
发出请求的客户端不知道哪个对象最终会处理这个请求,这样系统的更改在不影响客户端的情况下动态的组织和分配责任.
职责链模式的主要目的:解耦
经由传递请求沿着一个潜在接收者串行以降低传送者与接收者耦合性。
职责链参与者:
1) handler: 处理请求的接口
2) ConcreteHandler:负责处理请求,能够访问继任者,
如果它能够处理请求,它就处理; 否则,会将请求传递给它的继任者
3) client:初始化一个请求,传递给concreteHandler