连接不同的类型(Connecting different types)
适配器(Adapter)
适配器获得一种类型,并且为其他类型产生一个接口。
当你获得这种类型,并且需要另外类型,适配器能解决这个问题。唯一需要作的就是产生另外那种类,有很多种方式你可以完成这个适配器。
//: adapter:SimpleAdapter.java
// "Object Adapter" from GoF diagram
package adapter;
import junit.framework.*;
class Target {
public void request() {}
}
class Adaptee {
public void specificRequest() {
System.out.println("Adaptee: SpecificRequest");
}
}
class Adapter extends Target {
private Adaptee adaptee;
public Adapter(Adaptee a) {
adaptee = a;
}
public void request() {
adaptee.specificRequest();
}
}
public class SimpleAdapter extends TestCase {
Adaptee a = new Adaptee();
Target t = new Adapter(a);
public void test() {
t.request();
}
public static void main(String args[]) {
junit.textui.TestRunner.run(SimpleAdapter.class);
}
} ///:~
//: adapter:AdapterVariations.java
// Variations on the Adapter pattern.
package adapter;
import junit.framework.*;
class WhatIHave {
public void g() {}
public void h() {}
}
interface WhatIWant {
void f();
}
class SurrogateAdapter implements WhatIWant {
WhatIHave whatIHave;
public SurrogateAdapter(WhatIHave wih) {
whatIHave = wih;
}
public void f() {
// Implement behavior using
// methods in WhatIHave:
whatIHave.g();
whatIHave.h();
}
}
class WhatIUse {
public void op(WhatIWant wiw) {
wiw.f();
}
}
// Approach 2: build adapter use into op():
class WhatIUse2 extends WhatIUse {
public void op(WhatIHave wih) {
new SurrogateAdapter(wih).f();
}
}
// Approach 3: build adapter into WhatIHave:
class WhatIHave2 extends WhatIHave
implements WhatIWant {
public void f() {
g();
h();
}
}
// Approach 4: use an inner class:
class WhatIHave3 extends WhatIHave {
private class InnerAdapter implements WhatIWant{
public void f() {
g();
h();
}
}
public WhatIWant whatIWant() {
return new InnerAdapter();
}
}
public class AdapterVariations extends TestCase {
WhatIUse whatIUse = new WhatIUse();
WhatIHave whatIHave = new WhatIHave();
WhatIWant adapt= new SurrogateAdapter(whatIHave);
WhatIUse2 whatIUse2 = new WhatIUse2();
WhatIHave2 whatIHave2 = new WhatIHave2();
WhatIHave3 whatIHave3 = new WhatIHave3();
public void test() {
whatIUse.op(adapt);
// Approach 2:
whatIUse2.op(whatIHave);
// Approach 3:
whatIUse.op(whatIHave2);
// Approach 4:
whatIUse.op(whatIHave3.whatIWant());
}
public static void main(String args[]) {
junit.textui.TestRunner.run(AdapterVariations.class);
}
} ///:~
这里,我用术语“代理器”随意的说,因为在设计模式中定义一个代理器必须有同样的接口和它要代理的对象。然而,如果你合并这两个词:“代理适配器”,也许更有理由。
连接桥模式(Bridge)
当研究连接桥模式时,我发现在GoF中它是描述最少的一个。我得出了这个结论,当阅读Alan Shalloway的《设计模式说明》中有关连接桥模式的时候,他开始被GoF描述的设计模式搞得不知所以。
再一次谈论中,我与两个曾经写过和讨论过设计模式的人讨论,包括连接桥模式。在两个分开的讨论中,我有完全不同的观点关于桥模式的结构。
带着疑惑,我重新研读GoF,并且意识到上面那两位的观点不同于这本书。并且,我发现对桥模式描述的不怎么好,尤其是不是用一般的结构图描述的,根本毫无用处,除了在结构图中描述特定的例子。仅仅当你凝视一会才能对桥模式有所领悟。
理解桥模式的一个重要优点,它经常是写代码有用的一个结构。你也许会选择对象在一个编译时或运行时特定的位置,但是桥模式的目的是允许你结构化代码如此能容易的添加新的前端对象,这个前端对象被新类型的后端对象功能性的实现。这样前端和后端的能够独立于彼此变化。
前端的类同每一个类都有完全不同的接口。他们的共性是能够便利的实现他们的功能从任何不同种类的后端对象中。后端的对象也不必有同样的接口。后端的对象唯一必须作的共性是实现同种的功能。例如,一组不同的方式实现一个图形库或者一套不同的数据存贮方案。
桥模式是一个真正的代码组织工具允许你添加新的任何数量的前端服务,这些服务实现他们的操作通过代理任何后端的选项。使用桥模式,你能够实现这个不用常规的可能的大量组合。但是要记住桥模式的变化矢量典型的发生在编码时:他组织你的代码当你处理不断增长的选项量,为了实现功能的缘故。
这有个例子,它的唯一目的是论证桥模式的结构。
//: bridge:BridgeStructure.java
// A demonstration of the structure and operation
// of the Bridge Pattern.
package bridge;
import junit.framework.*;
class Abstraction {
private Implementation implementation;
public Abstraction(Implementation imp) {
implementation = imp;
}
// Abstraction used by the various front-end
// objects in order to implement their
// different interfaces.
public void service1() {
// Implement this feature using some
// combination of back-end implementation:
implementation.facility1();
implementation.facility2();
}
public void service2() {
// Implement this feature using some other
// combination of back-end implementation:
implementation.facility2();
implementation.facility3();
}
public void service3() {
// Implement this feature using some other
// combination of back-end implementation:
implementation.facility1();
implementation.facility2();
implementation.facility4();
}
// For use by subclasses:
protected Implementation getImplementation() {
return implementation;
}
}
class ClientService1 extends Abstraction {
public ClientService1(Implementation imp) { super(imp); }
public void serviceA() {
service1();
service2();
}
public void serviceB() {
service3();
}
}
class ClientService2 extends Abstraction {
public ClientService2(Implementation imp) { super(imp); }
public void serviceC() {
service2();
service3();
}
public void serviceD() {
service1();
service3();
}
public void serviceE() {
getImplementation().facility3();
}
}
interface Implementation {
// The common implementation provided by the
// back-end objects, each in their own way.
void facility1();
void facility2();
void facility3();
void facility4();
}
class Library1 {
public void method1() {
System.out.println("Library1.method1()");
}
public void method2() {
System.out.println("Library1.method2()");
}
}
class Library2 {
public void operation1() {
System.out.println("Library2.operation1()");
}
public void operation2() {
System.out.println("Library2.operation2()");
}
public void operation3() {
System.out.println("Library2.operation3()");
}
}
class Implementation1 implements Implementation {
// Each facility delegates to a different library
// in order to fulfill the obligations.
private Library1 delegate = new Library1();
public void facility1() {
System.out.println("Implementation1.facility1");
delegate.method1();
}
public void facility2() {
System.out.println("Implementation1.facility2");
delegate.method2();
}
public void facility3() {
System.out.println("Implementation1.facility3");
delegate.method2();
delegate.method1();
}
public void facility4() {
System.out.println("Implementation1.facility4");
delegate.method1();
}
}
class Implementation2 implements Implementation {
private Library2 delegate = new Library2();
public void facility1() {
System.out.println("Implementation2.facility1");
delegate.operation1();
}
public void facility2() {
System.out.println("Implementation2.facility2");
delegate.operation2();
}
public void facility3() {
System.out.println("Implementation2.facility3");
delegate.operation3();
}
public void facility4() {
System.out.println("Implementation2.facility4");
delegate.operation1();
}
}
public class BridgeStructure extends TestCase {
public void test1() {
// Here, the implementation is determined by
// the client at creation time:
ClientService1 cs1 =
new ClientService1(new Implementation1());
cs1.serviceA();
cs1.serviceB();
}
public void test2() {
ClientService1 cs1 =
new ClientService1(new Implementation2());
cs1.serviceA();
cs1.serviceB();
}
public void test3() {
ClientService2 cs2 =
new ClientService2(new Implementation1());
cs2.serviceC();
cs2.serviceD();
cs2.serviceE();
}
public void test4() {
ClientService2 cs2 =
new ClientService2(new Implementation2());
cs2.serviceC();
cs2.serviceD();
cs2.serviceE();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(BridgeStructure.class);
}
} ///:~
前端的基类提供操作被用来满足前端的派生类,后端也同样如此。这样,任何后端的派生类能够用来被执行碑前端类需要的操作。注意,桥接发生在下面的步骤顺序,他们的每一个停工了一个抽象层。这里,Implementation被定义作为一个接口来强调所有的功能被后端的派生类实现,没有一个是用基类来实现的。
后端的派生类执行基类定义的操作通过代理给对象(如这个例子中的Library1和Library2),他么典型的有根本不同的接口,但是不知何故提供同样的功能(这是桥模式的一个重要目的)。有效的,每一个后端的实现是一个适配器到不同的库或者工具,以不同的方式实现预期的功能。
1. 修改BridgeStructure.java 文件,使用工厂来实现。
2. 修改 BridgeStructure.java 文件,在前端使用代理而非后端的继承. 通过使用代理而非继承你会看到有什么好处吗?
3. 用一个抽象来创建一个桥模式的例子:联合数组。允许你取元素通过传进一个键对象。构造器在数组中提供一个初始的key-value对集合。当你仅仅取元素的时候,数组被使用,但是当你设置新的key-value对的时候,实现转换到一个map上。
4. 使用桥模式随同 java.util.collections 中的集合类ArrayList创建堆栈和序列类。当系统能够运行的时候,添加一个双向序列类。添加一个 LinkedList 。 这些步骤将论证桥模式如何能够允许你添加一个新的前端类和后端类在你的代码中,伴随着最小的影响。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/25966/viewspace-53323/ ,如需转载,请注明出处,否则将追究法律责任。