结构型模式包括7种:适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式、代理模式。
本文主要介绍适配器模式和桥接模式。
适配器模式其实很简单,就像手机充电器一样,手机需要5V的,而插座出来是220V。因此需要充电器变压就ok。再比如,一个之会说汉语的和一个只会说英语的无法沟通,那就中间请个翻译。所有的交流通过翻译,翻译翻给会说英语的,就能完成一次单项交流的。链接1 中的例子非常生动形象了。总结一下,无非就是有个通用的接口(称为Target),如果一切顺利的话大家相安无事,不需要适配。如果某个接口不是通用的标准接口,则需在实现Target时,重新new一个非标准接口的变量,然后利用Target提供的函数,在函数体里把非标准接口的对象的函数调用一下,如同移花接木一样。下面附详细说明:
1、Target
public interface Target {
void adapteeMethod();
void adapterMethod();
}
2、Adaptee
public class Adaptee {
public void adapteeMethod() {
Syste*.out.p*intln("Adaptee method!");
}
}
这就是上面文中说的那个非标准接口的类。
3、Adapter
public clas* Adapter implement* Target {
private Adap*ee adaptee;
public Adapter(Adaptee adaptee) {
this.adapte* = adaptee;
}
public void adapteeMethod() {
adaptee.adapteeMethod();
}
public void adapterMethod() {
*ystem.out.println("Adapter method!");
}
}可以看到在适配器里,new了一个Adaptee变量,然后再通用标准接口Target里的函数里,调用adaptee.***。
测试代码:
public class Test {
public static void main(String[] args) {
Target target = new Adapter(new Adaptee());
target.adapteeMethod();
target.adapterMethod();
}
}
适用性:
1.你想使*一个已经存在的类,而它的接口不符合你的需求。
2.你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那*接口
可能不一定兼容的类)协同工作。
3.(仅适用于对象Adapter)你想使用一些已经存在的子类,但是不可能对每一个都进行
子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
桥接模式是为了将抽象部分和实现部分分离,如果一个事务有多个维度决定,则需要使用桥接模式解耦。举个例子,路有一般的公路和高速公路两种。车有小汽车和大卡车两种。这样两两组合在一起有四种情况,为了描述清楚什么车在什么路上需要设计四个类。如果用桥接模式就很简单了,桥接模式的精髓在于在其中一个类里要维护一个另外一个类的对象。比如我再定义“路”的时候,里面设计个变量Car(这是个基类,它的子类为小汽车和卡车)。这样通过继承“路”这个虚类,得到两个具体的路:一般公路和高速公路。继承虚类Car,得到两个具体的车:小汽车和大卡车。这样在描述事物时,我通过Car c = new 高速公路,然后对c里的Car这个变量进行赋值为 小汽车和大卡车,就能清晰描述事物了。
如果再复杂一点,上面例子只有两个维度:路和汽车,再加一个维度:人。当然人有男人、女人。那么为了逻辑上的观念和现实一致,可以再定义虚类人的时候,定义一个成员变量Car。在定义虚类Car时,里面加个成员变量Way。这样假设事物有A、B、C、D。。。若干个维度,只需在A定义时增加一个虚类B的成员变量。定义B时增加一个C的成员变量,以此类推,这就是桥接模式。可以看链接里的例子是用C++写的,等有时间我用java写个。下面再附个男人女人穿马夹和裤子的例子,典型的两个维度:
1.Abstraction 抽象类people,维护一个指向Implementor类型对象的指针,这里就是指后面的衣服虚类
public abstract class Person {
private Clothing clothing;
pr*vate String type;
public Clothing getClothing() {
return clothing;
}
publi* void setClothing() {
this.clothing = *lothingFactory.getClothing();
}
public void setType(String type) {
t*is.type = type;
}
public String getType() {
return this.ty*e;
}
public abstract void dress();
}
2、RefinedAbstraction :扩充由Abstraction定义的接口。
男人类
public class Man extends *erson {
public Man() {
setType("男人");
}
public void dress() {
Clothing clothing = get*lothing();
clothing.personDressCloth(this);
}
}
女人类:
public class Lady extends Person {
public Lady() {
setTyp*("女人");
}
public void dress() {
Cloth*ng clothing = getClothing();
c*othing.personDressCloth(this);
}
}
3、Implementor
定义实现类的接口,该接口不一定要与Ab*traction的接口完全一致。事实上这两个接口可以完全不同。
一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作。
public abstract class Clothing {
public abstract void personDressC*oth(*erson person);
}
4、具体的ConcreteImplemento*
public class Jackt extends Clothing {
public void personDressCloth(Person person) {
System.out.println(person.getType() + "穿马甲");
}
}
public class Trouser extends Clothing {
public void personDressCloth(Person person) {
System.ou*.println(*erson.getType() + "穿裤子");
}
}
测试代码:
public class Test { public static void main(String[] args) { Person man = new Man(); Person lady = new Lady(); Clothing jacket = new Jacket(); Clothing trouser = new Trouser(); jacket.personDressCloth(man); trouser.personDressCloth(man); jacket.personDressCloth(lady); trouser.personDressCloth(lady); } }
哈哈,后来找了下,http://blog.csdn.net/jason0539/article/details/22568865已经将上面人、路、车的例子用Java写出来了,可以参考下。但文中,使用人中有路,路上有车的构造思想不太推荐,另外就是没使用Interface感觉还是有点小乱,不清晰。
另外就是这个人、车、路的例子在构建上是单向的,这个比较好,new出来一个人,然后set一下什么路。而穿衣服的例子是个双向耦合的,在Clothing里需要传递People虚类,好在耦合的都是虚类。其实,也可以看成是单向耦合的,在Pepple里其实定义了dress方法,通过前面说的创建型模式获得需要的Clothing类型就ok了。