适配器模式(Adapter)
将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。
有一个Source类,拥有一个方法,待适配,目标接口时Targetable,通过Adapter类,将Source的功能扩展到Targetable里。
主要分成三类:类的适配器模式、对象的适配器模式、接口的适配器模式。
类的适配器模式
当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
原有类: package Adapter;
public class Original { public void originalMethod(){ System.out.println("original..."); } } |
接口: package Adapter;
public interface ClassAdapterInterface { public void originalMethod();
public void newMethod();
} |
新类: package Adapter;
public class ClassAdapter extends Original implements ClassAdapterInterface { @Override public void newMethod() { // TODO Auto-generated method stub System.out.println("new..."); } }
|
测试类: package Adapter;
public class Client {
/** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ClassAdapter ca = new ClassAdapter(); ca.originalMethod(); ca.newMethod(); } }
|
对象的适配模式
当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Adapter类,持有原类的一个实例,在Adapter类的方法中,调用实例的方法就行。
新类: package Adapter;
public class ObjectAdapter implements AdapterInterface { private Original original;
ObjectAdapter(Original original){ super(); this.original = original;
}
@Override public void originalMethod() { // TODO Auto-generated method stub original.originalMethod();
}
@Override public void newMethod() { // TODO Auto-generated method stub System.out.println("new");
}
}
|
测试类: package Adapter;
public class Client {
/** * @param args */ public static void main(String[] args) { Original original = new Original(); ObjectAdapter oa = new ObjectAdapter(original); oa.originalMethod(); oa.newMethod(); } }
|
接口的适配器模式
当不希望实现一个接口中所有的方法时,可以创建一个抽象类Adapter实现所有方法,我们写别的类的时候,继承抽象类即可。
接口: package Adapter;
public interface AdapterInterface { public void originalMethod();
public void newMethod();
}
|
抽象类: package Adapter;
public abstract class Adapter implements AdapterInterface {
@Override public void originalMethod() { // TODO Auto-generated method stub
}
@Override public void newMethod() { // TODO Auto-generated method stub
}
}
|
实现类: // InterfaceAdapter1 package Adapter;
public class InterfaceAdapter1 extends Adapter{ public void newMethod() { // TODO Auto-generated method stub System.out.println("new..."); } }
// InterfaceAdapter2 package Adapter;
public class InterfaceAdapter2 extends Adapter{ public void originalMethod() { // TODO Auto-generated method stub System.out.println("original..."); } }
|
测试类: package Adapter;
public class Client {
/** * @param args */ public static void main(String[] args) {
InterfaceAdapter1 ia = new InterfaceAdapter1(); ia.originalMethod(); ia.newMethod(); } }
|
桥接模式(Bridge)
把事物和其具体实现分开(抽象化与实现化解耦),使他们可以各自独立的变化。
接口: package Bridge;
public interface Sourcable { public void method(); }
|
实现类: // SourceSub1 package Bridge;
public class SourceSub1 implements Sourcable {
@Override public void method() { // TODO Auto-generated method stub System.out.println("1..."); }
}
// SourceSub2 package Bridge;
public class SourceSub2 implements Sourcable {
@Override public void method() { // TODO Auto-generated method stub System.out.println("2..."); }
}
|
桥: package Bridge;
public abstract class Bridge {
public abstract void bridge(Sourcable Source);
}
|
桥的实现: // Action1 package Bridge;
public class Action1 extends Bridge {
@Override public void bridge(Sourcable Source) { // TODO Auto-generated method stub System.out.println("a1..."); Source.method(); }
} // Action2 package Bridge;
public class Action2 extends Bridge {
@Override public void bridge(Sourcable Source) { // TODO Auto-generated method stub System.out.println("a2..."); Source.method(); }
}
|
测试类: package Bridge;
public class Client {
/** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Action1 a1= new Action1(); a1.bridge(new SourceSub1()); a1.bridge(new SourceSub2());
Action2 a2= new Action2(); a2.bridge(new SourceSub1()); a2.bridge(new SourceSub2()); }
}
|
总结
将抽象化与实现化解耦,使得二者可以独立变化。
假设你的电脑是双系统(WinXP、Win7),而且都安装了mysql、oracle、sqlserver、DB2这4种数据库,那么你有2*4种选择去连接数据库。按平常的写法,咱要写2*4个类,但是使用了桥接模式,你只需写2+4个类,可以看出桥接模式其实就是一种将N*M转化成N+M组合的思想。(middleware的思想)
合成模式(Composite)
将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树,数等。
树类: package Composite;
import java.util.ArrayList; import java.util.List;
public class TreeNode { private String name; private TreeNode parent; private List<TreeNode> children = new ArrayList<TreeNode>();
public TreeNode(String name){ this.name = name; }
public String getName(){ return name; } public void setName(String name){ this.name = name; } public TreeNode getParent(){ return this.parent; } public void setParent(TreeNode parent){ this.parent = parent; } public List<TreeNode> getChildren(){ return this.children; } public void addChild(TreeNode child){ this.children.add(child); } public void removeChild(TreeNode child){ this.children.remove(child); } }
|
测试类: package Composite;
public class Client {
/** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub TreeNode a = new TreeNode("a"); TreeNode b = new TreeNode("b"); TreeNode c = new TreeNode("c"); TreeNode d = new TreeNode("d");
a.addChild(b); a.addChild(c); a.setParent(d);
System.out.println(a.getParent().getName()); for(TreeNode t : a.getChildren()){ System.out.println(t.getName()); } }
}
|
装饰模式(Decorator)
动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更具有弹性的替代方案。对于装饰者模式。
接口: package Decorator;
public interface Sourcable { public void method(); }
|
原有类: package Decorator;
public class Source implements Sourcable {
@Override public void method() { // TODO Auto-generated method stub System.out.println("source..."); }
}
|
包装类: package Decorator;
public class Decorator implements Sourcable {
private Source source;
public Decorator(Source source){ this.source = source; } @Override public void method() { // TODO Auto-generated method stub System.out.println("1 decorator..."); source.method(); System.out.println("2 decorator..."); }
}
|
测试类: package Decorator;
public class Client {
/** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Source s = new Source(); Decorator d = new Decorator(s); d.method(); }
}
|
应用场景
1、需要扩展一个类的功能。
2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)
缺点:产生过多相似的对象,不易排错!
外观模式(Facade)
将一个系统划分成若干个子系统有利于降低系统的复杂性。一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小。外观模式通过引入一个外观对象,为子系统中较一般的设施提供了一个单一而简单的界面。
//子系统1 package Facade;
public class CPU { public void startup(){ System.out.println("CPU startup..."); } public void shutdown(){ System.out.println("CPU shutdown..."); } } //子系统2 package Facade;
public class Disk { public void startup(){ System.out.println("Disk startup..."); } public void shutdown(){ System.out.println("Disk shutdown..."); } }
|
//外观类 package Facade;
public class Facade { private CPU c; private Disk d;
public Facade(){ this.c = new CPU(); this.d = new Disk(); }
public void startup(){ c.startup(); d.startup(); System.out.println("Facade startup..."); } public void shutdown(){ c.shutdown(); d.shutdown(); System.out.println("Facade shutdown..."); } }
|
//测试类 package Facade;
public class Client {
/** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Facade f = new Facade(); f.startup(); f.shutdown(); }
}
|
享元模式(Flyweight)
主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。。在某种程度上,你可以把单例看成是享元的一种特例。
//共享对象,抽象类 package FlyWeight;
public abstract class FlyWeight { public abstract void method(); }
|
//共享对象,实现类 package FlyWeight;
public class SubFlyWeight extends FlyWeight { private String key;
public SubFlyWeight(String key){ this.key = key; }
@Override public void method() { // TODO Auto-generated method stub System.out.println("String:" + this.key); }
}
|
//生产共享对象工厂 package FlyWeight;
import java.util.HashMap; import java.util.Map;
public class FlyWeightFactory { private Map<String, FlyWeight> map = new HashMap<String, FlyWeight>();
public FlyWeight getFlyWeight(String key){ FlyWeight fw = map.get(key); if(fw == null){ fw = new SubFlyWeight(key); map.put(key, fw); } return fw; }
public int getCount(){ return map.size(); } }
|
//测试类 package FlyWeight;
public class Client {
/** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub FlyWeightFactory fwf = new FlyWeightFactory(); FlyWeight fw1 = fwf.getFlyWeight("aaa"); FlyWeight fw2 = fwf.getFlyWeight("aaa");
System.out.println(fw1 == fw2); fw1.method(); fw2.method();
FlyWeight fw3 = fwf.getFlyWeight("bbb"); System.out.println(fw1 == fw3); fw1.method(); fw3.method(); }
}
|
代理模式(Proxy)
代理模式就是多一个代理类出来,替原对象进行一些操作。
//接口 package Proxy;
public interface Sourcable { public void method(); }
|
//原有类 package Proxy;
public class Source implements Sourcable {
@Override public void method() { // TODO Auto-generated method stub System.out.println("source..."); }
}
|
//代理类 package Proxy;
public class Proxy implements Sourcable { private Source s;
public Proxy(){ super(); s = new Source(); } @Override public void method() { // TODO Auto-generated method stub System.out.println("Proxy..."); s.method(); }
}
|
//测试类 package Proxy;
public class Client {
/** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Sourcable p = new Proxy(); p.method(); }
} |
应用场景
如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:
1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。
2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。
使用代理模式,可以将功能划分的更加清晰,有助于后期维护!
总结
Adapter, Bridge, Facade
Adapter主要是为了解决两个已有的接口之间不匹配的问题。它不考虑这些接口是怎么实现的,也不考虑它们各自可能会如何演化。这种方式不需要对两个独立设计的类中的任何一个进行重新设计,就能够使它们协同合作。当发现两个不兼容的类必须同时工作时,就需要使用Adapter模式,其目的一般是为了避免代码重复。
Bridge对抽象接口和它的实现部分进行桥接。虽然这一模式允许修改实现它的类,它仍然为用户提供一个稳定的接口。Bridge的使用者必须事先知道:一个抽象加盖有多个实现部分,并且抽象和实现两者之间独立演化。
Façade定义一个新的接口,而Adapter则复用原有接口。
Composite, Decorator, Proxy
Composite和Decorator都基于递归组合来组织可变数目的对象。
Decorator旨在使你能够不需要生成子类即可给对象添加职责。避免了静态实现所有功能的组合。
Composite旨在构造类,是多个相关的对象能够以统一的方式处理,而多重对象可以被当做一个对象来处理。
Proxy通Decorator一样,描述了怎样为对象提供一定程度上的间接引用,对象的实现部分都保留了指向另一个对象的指针,它们向这个对象发送请求。但是,Proxy不能动态地添加或分离性质,它也不是为递归组合而设计的。它的目的是,当直接访问一个实体不方便或不符合需要时,为这个实体提供一个替代者。
在Proxy中,实体定义了关键功能,而Proxy提供对它的访问。
在Decorator中,组件仅提供了部分功能,而一个或者多个Decorator负责完成其他功能。
Reference
设计模式:可复用面向对象软件的基础