类适配
对象适配
注: 1)将一个类的接口转换成客户所希望的另外一个接口,使得原来由于接口不兼容而不能一起工作的那些类可以一起工作。
2) Ada pter属于一个中间类,负责协调Client与Target之间的调用转发。
3)由于Java只支持单继承,所以,在Java中从Adapter到Target的继承都不出现。
i. 可以很容易的把原有的(Adaptee)操作,移植到新的应用当中。
i. 你想使用一个已经存在的类,而她的接口不符合你的要求。
ii. 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作。
iii. 你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配他们的接口。对象适配器可以适配她的父接口。
i. 类适配:
public class Target{
public void request(){…}
}
public class Ada ptee{
public void requestB(){…}
}
public class Ada pter extends Adaptee{
public void request(){
super.requestB();
}
}
ii. 对象适配:
public class Target{
public void request(){…}
}
public class Ada ptee{
public void requestB(){…}
}
public class Ada pter extends Target{
private Ada ptee adaptee = new Ada ptee();
public void request(){
adaptee.requestB();
}
}
i. 用于将一个接口转化为另一个。
ii. 在Adapter模式中有三个类Target,Adapter,Adaptee。 Ada pter要继承Target是从结构上考虑,从而在调用Target的地方均可用Adapter。而Adapter要实现Adaptee是从功能上考虑,达到重用Adaptee中功能的作用。
iii. 如果AWT应用程序要使用Swing当中新的类,可以提供一组从Swing到AWT的适配器。
2. Bridge模式
注: 1)将抽象部分(Abstraction)与他的实现部分(Implementor)分离,使他们都可以独立的变化。
2)对于Client来说,Implementor部分的实现细节得到隐藏。
i. 降低了各部分之间的耦合程度,隐藏了实现细节。便于各部分的独立更新。
i. 你不希望在抽象和她的实现部分之间有一个固定的绑定关系。例如这种情况可能是因为在程序运行时刻,实现部分可以被选择或者切换。
ii. 类的抽象以及他的实现部分都应该可以通过生成子类的方法加以扩充。这时,Bridge模式使你可以对不同的抽象接口和实现部分进行组合,并分别对他们进行扩充。
iii. 对一个抽象的实现部分的修改应对客户不产生影响。
iv. 你想对客户完全隐藏抽象的实现部分。
v. 有许多类需要生成,这样一个类层次结构说明你必须将一个对象分解成两个部分。
vi. 你想在多个对象间共享实现(可使用引用计数),但同时要求客户并不知道这一点。
public class Abstraction{
private Implementor imp = new ImplementorA();
public void operation(){
imp.operation();
}
}
public interface Implementor{
public void operation();
}
public class ImplementorA implements Implementor{
public void operation(){…}
}
public class ImplementorB implements Implementor{
public void operation(){…}
}
i. 用于将客户端和实现类进行分离,使得两部分都能进行单独的修改。
ii. 对Abstraction的修改可以增加Client可使用的功能。
iii. 对Implementor的修改可以增加Abstraction可使用的操作。
iv. 对Abstraction和Implementor的修改和定制都是独立的,且对Client透明。
v. 在Java的数据库访问当中,把功能实现分成两部分,一部分是供应用程序调用的接口,另一部分是负责功能实现的SPI。
3. Composite模式
注: 1)将对象组合成树形结构,以表示“整体-部分”的层次结构。
2)使得对单个对象的操作和对组合对象的操作具有一致性。
i. 对节点(Composite)和对叶子(Leaf)的处理一致,使得客户的操作变得简单。(对Leaf和Composite可以使用相同的方法处理)
ii. 可以很简单的添加新的类型,但也可能导致系统过于一般化,不能加入某些特定限制。(操作都在Component中定义,子类只能修改方法的实现,但不能增加特定的方法)
i. 你想表示对象的“整体-部分”层次结构。
ii. 你希望用户忽略组合对象与单个对象的不同。
public abstract class Component{
public abstract void operation();
public void add(Component child){…}
public void remove(Component child){…}
public Component getChild(int index){…}
}
public class Leaf extends Component{
public void operation(){…}
}
public void Composite extends Component{
public void operation(){…}
}
i. 是对象的一个集合,其中的每一个对象要么是一个Composite,要么就是一个基础类。
ii. 在实现Composite模式时,要考虑以下几个问题:
1) 该模式没有在子节点当中记录父节点的信息,可以考虑添加。
2) 共享组件:即一个组件属于多个父组件,需要引入Flyweight模式。
3) 最大化Component接口:定义一个Leaf和Composite功能的并集。
4) 声明管理子部件操作:在根声明对子节点的增删操作,可增加透明性,但是会导致安全隐患,如在Leaf中执行节点的增删操作。在子节点中声明增删操作,保证了Leaf节点的安全,但丧失了透明性。
5) 节点删除:对于共享子节点,需要特别对待。
iii. Java中的JTree中用到的Node类,DOM中用到的Node类都是Composite模式的应用。
注: 1)动态地给一个对象增加额外的职责。
2)不是通过继承来实现。
3)只是对某一个类实例,而不是对整个类增加功能。
i. 可以将多个Decorator进行嵌套使用。
ii. 不需要通过继承,而给类实例动态增加额外的功能。(但可能产生很多额外的小类)
i. 在不影响其他对象的情况下,以动态,透明的方式给单个对象添加职责。(因为不是通过继承等方式扩展功能)
ii. 处理那些可以撤销的职责。(由于职责只是动态的加到对象实例上,所以,当不需要该功能时,只要不增加修饰即可)
iii. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长(例如,如有子功能A,B,C则不同的组合方式将有3+6+6种)。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。(类被定义成final)
public class Component{
public void operation(){…}
}
public class ComponentA extends Component{
public void operation(){…}
}
public class Decorator extends Component{
private Component component;
public void operation(){
component.operation();
}
}
public class DecoratorB extends Decorator{
public void operation(){
super.operation();
addedOperation();
}
private void addedOperation(){…}
}
i. 环绕在一个给定类的外围,为给定的类添加额外的功能,而对于不需要改变的行为则仍由给定类完成。
ii. Decorator改变对象的职责,Adapter改变对象的接口。
iii. Decorator改变对象的外观,Strategy改变对象的内核。
iv. Decorator可以看作退化了的,仅有一个组件的Composite。然而,Decorator在于给对象添加一些额外的功能,Composite在于对象聚集。
v. Java的IO包和Swing中的Border包是Decorator的一个具体应用。
5. Facade模式
注: 1)为子系统中的一组接口提供一个一致的界面。Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
i. 屏蔽掉底层子系统的复杂性,给用户一个比较简洁的调用界面。
ii. 使用户代码和底层实现分离,降低了耦合度。
iii. 减少了客户端与子系统之间的通信次数。
i. 当为一个复杂子系统提供一个简单接口时。Facade模式提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过Facade层。
ii. 当客户程序与抽象类的实现部分之间存在着很大的依赖性,通过引入Facade,可以将子系统与客户端进行分离,降低耦合性,提高独立性和移植性。
iii. 当你需要构建一个层次结构的子系统时,使用Facade模式,可以定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让他们仅通过Facade进行通信,从而简化了他们之间的依赖关系。
public class Facade{
private SubsystemA subA = new SubsystemA();
private SubsystemB subB = new SubsystemB();
public void operation(){
subA.doSomething();
subB.doAnotherthing();
}
}
public class SubsystemA{
public void doSomething(){}
}
public class SubsystemB{
public void doAnotherthing(){}
}
i. 将一个复杂的对象结构进行组合,并形成一个新的,简化了的界面。
ii. 可以用抽象类实现Facade,而他的具体子类对应于不同的子系统实现,这可以进一步降低客户与子系统间的耦合度。(可进行整个子系统的替换)
iii. 在J2EE中,Facade模式用于代替客户端实现对多个Session Bean的访问。
注: 1)运用共享技术有效的支持大量细粒度的对象。
2)被共享的对象有可能是一个Sigleton。
3)共有的属性保存在类内部,个别的属性放在类外部的数组或者Vector中。
i. 减少了所需要的实例。
i. 一个应用程序使用了大量对象。
ii. 完全由于使用大量的对象,造成很大的存储开销。(通过共享实例,减少存储开销)
iii. 对象的大多数状态都可变为外部状态。
public class FlyweightFactory{
private Flyweight[] fly;
public Flyweight getFlyweight(int key){
if(fly[key] != null){
return fly[key];
}else{
fly[key] = new FlyweightA();
return fly[key];
}
}
}
public class Flyweight{
public void operation(){…}
}
public class FlyweightA extends Flyweight{
public void operation(){…}
}
i. 通过将类的某些数据移到类的外部,并通过各种方法将这些数据传到类的内部来提供一种方法,以限制一些小的,相似的类实例的生成。(有点类似Prototype模式)
ii. Flyweight不能对他所运行的场景作出任何假设,类似于EJB中的Stateless Session Bean。
iii. Flyweight对象必须是可共享的,她所存储的状态必须是内部的,即她必须独立于Flyweight对象的场景。因此,一般由一个Flyweight Pool对Flyweight进行生命期管理。
iv. 可以用两种方法来节约存储:用共享减少内部状态的消耗,用计算时间换取对外部状态的存储。
v. 共享还意味着某种形式的引用计数和垃圾回收。
7. Proxy模式
注: 1)为其他对象提供一种代理以控制这个对象的访问。
2)Proxy与该对象具有一致得接口,她介入对所代理对象的请求中,执行一些额外的操作。
i. 缩短反应时间。(可以在Proxy内启动一个线程,使方法调用可以马上返回)
ii. 可进行一定的权限管理。(所有对RealSubject的访问,都需要先经过Proxy进行过滤)
i. 远程代理:为一个对象在不同的地址空间提供局部代表。(类似于RMI中的Stub)
ii. 虚代理:根据需要创建一个开销很大的对象。(延迟大对象的初始化时刻,由虚代理暂时代表实际对象)
iii. 保护代理:控制对原始对象的访问,保护代理用于对象应该有不同的访问权限的时候。
iv. 智能代理:取代了简单的指针,她在访问对象时执行一些附加的操作。她的典型用途包括对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放她。
v. 当第一次引用一个持久对象时,将他装入内存。(延迟持久对象的装载时刻)
vi. 在访问一个实际对象前,检查是否已经锁定了她,以确保其他对象不能改变她。(由于对RealSubject的访问需要先经过Proxy,所以,可以在Proxy内以访问计数或者synchronized等方式加锁)
vii. Java在处理图片时,使用了该模式。(虚代理)
public interface Subject{
public void request();
}
public class RealSubject implements Subject{
public void request(){}
}
public class Proxy implements Subject{
private void RealSubject real;
public void request(){
real.request();
}
}
i. 为一个复杂的,要实例化非常昂贵的类提供一个简单的占位类。
a) Ada pter主要是为了解决两个已有接口间的不匹配,而不考虑这些接口的实现和变化。
b) Bridge则对抽象接口与她的实现部分进行分离。
i. Ada pter的目的是为了避免代码重复,发生在类设计好以后
ii. Bridge的目的是为了降低耦合,发生在类设计以前。
c) Decorator旨在使你能够不需要子类化即可给对象添加额外的职责。
d) Composite旨在构造类,使多个相关的对象能够以统一的方式处理,她重点不在于修饰,而在于表示。
e) Proxy模式不能动态添加或分离性质,他也不是为递归组合而设计,其目的是当直接访问一个实体不方便或不符合需要时,为这个实体提供一个替代者。