Java:设计模式之适配器Adapter(续)

时间:2021-12-22 22:00:54

Java:设计模式之适配器模式Adapter


1.默认(缺省)适配器:

缺省适配(Default Adapter)模式为一个接口提供缺省实现,这样子类型可以从这个缺省实现进行扩展,而不必从原有接口进行扩展。作为适配器模式的一个特例,缺省是适配模式在JAVA语言中有着特殊的应用。

如果只是对接口的一部分感兴趣,采用默认适配器比较合适。

这样可以只针对这部分感兴趣的方法重新实现,而对于不感兴趣的部分采用默认设计。

这需要增加一个默认适配器。

具体代码:

缺省适配器:

package com.freestudio.designpattern;

//缺省适配器
public class MemoryDefaultAdapter implements IMemoryAdapter
{
// 实现接口默认设计
@Override
public void connectSD()
{
// TODO Auto-generated method stub
System.out.println("connectSD默认设计");
}

@Override
public void connectMiniSD()
{
// TODO Auto-generated method stub
System.out.println("connectMiniSD默认设计");
}

@Override
public void connectMicroSD()
{
// TODO Auto-generated method stub
System.out.println("connectMicroSD默认设计");
}

@Override
public void connectMMC()
{
// TODO Auto-generated method stub
System.out.println("connectMMC默认设计");
}

@Override
public void connectUSBDevice()
{
// TODO Auto-generated method stub
System.out.println("connectUSBDevice默认设计");
}

}

具体适配器:

package com.freestudio.designpattern;


//实现具体Adapter
public class MemoryAdapter3 extends MemoryDefaultAdapter
{
UsbConnector mUsbConnector = null;
// 只对SD感兴趣
@Override
public void connectSD()
{
System.out.println("connectSD:我只对connnectSD感兴趣,其他的采用默认的设计吧。");
if(mUsbConnector==null)
{
mUsbConnector = new UsbConnector();
}
mUsbConnector.connectUSBDevice();
}
}

客户端调用:

//缺省适配器
System.out.println("======================================");
IMemoryAdapter adapter = new MemoryAdapter3();
adapter.connectSD();
adapter.connectMicroSD();
adapter.connectMiniSD();

输出:

======================================
connectSD:我只对connnectSD感兴趣,其他的采用默认的设计吧。
UsbConnector:Connect to USB device
connectMicroSD默认设计
connectMiniSD默认设计


2.双向适配器(two-way adapter):

例子来自:http://userpages.umbc.edu/~tarr/dp/lectures/Adapter-2pp.pdf

使用适配器的一个潜在问题是:他们不对所有的客户都透明。被适配的对象不再兼容Adaptee的接口,因此并不是所有的Adaptee对象都可以被使用的地方都它都可以被使用。双向适配器提供了这样的透明性。在两个不同的客户需要不同的方式查看同一对象时,双向适配器尤其有用。


假设我们要打桩,有两种类:方形桩 圆形桩:

圆形桩:

package com.freestudio.designpattern;


//Adaptee
public class RoundPeg
{
public void insertIntoHole(String msg)
{
System.out.println("RoundPeg insertIntoHole(): " + msg);
}
}

方形桩:

package com.freestudio.designpattern;

//Target
public class SquarePeg
{
public void insert(String str)
{
System.out.println("SquarePeg insert(): " + str);
}
}

假设RoundPeg我们的客户端不了解或不熟悉,或者无法修改其源代码,可以通过双向Adapter来实现RoundPeg的访问:

PegAdapter:

package com.freestudio.designpattern;

/**
* Adapter适配器,将 RoundPeg适配到SquarePeg 接口实现的是SquarePeg的接口(继承自它).
*/
public class PegAdapter extends SquarePeg
{
//包含一个RoundPeg对象,使得他具有RoundPeg的行为
private RoundPeg roundPeg;

public PegAdapter(RoundPeg peg)
{
this.roundPeg = peg;
}

//改变行为为RoundPeg的行为
@Override
public void insert(String str)
{
roundPeg.insertIntoHole(str);
}
}

客户端调用:

static void TestTwoAdapter()
{
// Create some pegs.
RoundPeg roundPeg = new RoundPeg();
SquarePeg squarePeg = new SquarePeg();
// Do an insert using the square peg.
squarePeg.insert("Inserting square peg...");


//现在需要使用RoundPeg的insertIntoHole方法
//但是客户端只知道Peg的insert方法
//解决方法是:
//创建一个适配器,适配一个RoundReg到SquarePeg
PegAdapter adapter = new PegAdapter(roundPeg);
adapter.insert("Inserting round peg...");
}
输出:
SquarePeg insert(): Inserting square peg...
RoundPeg insertIntoHole(): Inserting round peg...

上述实现可以通过类似多重继承来实现,当然这Java中没有多重继承机制,只能通过interface来模拟:

这里只复制参考文档代码,不做解释。

/**
*The IRoundPeg interface.
*/
public interface IRoundPeg {
public void insertIntoHole(String msg);
}
/**
*The ISquarePeg interface.
*/
public interface ISquarePeg {
public void insert(String str);
}
// The RoundPeg class.
public class RoundPeg implements IRoundPeg {
public void insertIntoHole(String msg) {
System.out.println("RoundPeg insertIntoHole(): " + msg);
}
}
// The SquarePeg class.
public class SquarePeg implements ISquarePeg {
public void insert(String str) {
System.out.println("SquarePeg insert(): " + str);
}
}
/**
* The PegAdapter class.
* This is the two-way adapter class.
*/
public class PegAdapter implements ISquarePeg, IRoundPeg {
private RoundPeg roundPeg;
private SquarePeg squarePeg;
public PegAdapter(RoundPeg peg) {this.roundPeg = peg;}
public PegAdapter(SquarePeg peg) {this.squarePeg = peg;}
public void insert(String str) {roundPeg.insertIntoHole(str);}
public void insertIntoHole(String msg){squarePeg.insert(msg);}
}

// Test program for Pegs.
public class TestPegs {
public static void main(String args[]) {
// Create some pegs.
RoundPeg roundPeg = new RoundPeg();
SquarePeg squarePeg = new SquarePeg();
// Do an insert using the square peg.
squarePeg.insert("Inserting square peg...");
// Create a two-way adapter and do an insert with it.
ISquarePeg roundToSquare = new PegAdapter(roundPeg);
roundToSquare.insert("Inserting round peg...");
// Do an insert using the round peg.
roundPeg.insertIntoHole("Inserting round peg...");
// Create a two-way adapter and do an insert with it.
IRoundPeg squareToRound = new PegAdapter(squarePeg);
squareToRound.insertIntoHole("Inserting square peg...");
}
}


输出:

SquarePeg insert(): Inserting square peg...
RoundPeg insertIntoHole(): Inserting round peg...
RoundPeg insertIntoHole(): Inserting round peg...
SquarePeg insert(): Inserting square peg...

3.可插入的适配器(pluggable adapter):

可插入的适配器是一种可以动态适配多个类中的一个类的适配器。Java通过反射reflection来实现动态适配。通过反射可以动态的找到任何类和其公开的方法。(getClass/getMethods)

插件化适配器具有很高的灵活性,


//Adaptee

package com.freestudio.designpattern;

/**
* Adaptee
*
* @author andy
*
*/
public class PathFinder
{
public void explore()
{
System.out.println("explore");
}
}
//Target
package com.freestudio.designpattern;
/**
* Target
*
*/
public class Digger
{
public void dig()
{
System.out.println("Dig something");
}
}
//Target
package com.freestudio.designpattern;

/**
* Target
*
*/
public class Collector
{
public void collect()
{
System.out.println("Collect something");
}
}

//Adapter

package com.freestudio.designpattern;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
//Adapter
public class PluggableAdapterPathFinder
{
private PathFinder mPathFinder;
private HashMap<String, Method> mMap;

PluggableAdapterPathFinder(PathFinder pathFinder)
{
//绑定一个PathFinder对象(Adaptee)
this.mPathFinder = pathFinder;
mMap = new HashMap<String, Method>();
}

public void adapt(String className, String methodName)
{
System.out.println("class:"+className+" ,method:"+methodName);
//动态适配Target的方法,在需要时调用该方法
try
{
//通过类名反射得到相应的方法
Class _class = Class.forName(className);
Method method = _class.getMethod(methodName, null);
mMap.put(className, method);
}
catch (ClassNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (NoSuchMethodException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (SecurityException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//根据classname能正确的调用Target的方法
public void explore(String className)
{
mPathFinder.explore();
Method method = (Method) mMap.get(className);
try
{
//反射调用Method
method.invoke(Class.forName(className).newInstance(), null);
}
catch (IllegalAccessException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InvocationTargetException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InstantiationException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}

客户端代码:

static void TestPluggableAdapter()
{
PathFinder pathFinder = new PathFinder();
PluggableAdapterPathFinder adapter = new PluggableAdapterPathFinder(pathFinder);
adapter.adapt("com.freestudio.designpattern.Digger", "dig");
adapter.adapt("com.freestudio.designpattern.Collector", "collect");
adapter.explore("com.freestudio.designpattern.Digger");

adapter.explore("com.freestudio.designpattern.Collector");
}

输出:

class:com.freestudio.designpattern.Digger ,method:dig
class:com.freestudio.designpattern.Collector ,method:collect
explore
Dig something
explore
Collect something

参考:

http://www.cs.sjsu.edu/faculty/pearce/patterns2/pluggableAdapter.htm

 http://gossip.iteye.com/blog/69351