适配器模式

适配器(Adapter)模式

  在软件系统中,由于环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。

  那么如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?

  这就要利用Adapter模式

 

Adapter模式意图

  将一个类的接口转换成客户希望的另一个接口。

  Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

 

适配器(Adapter)模式的构成

  目标抽象角色(Target)

  定义客户要用的特定领域的接口。

  适配器(Adapter)

  调用另一个接口,作为一个转换器。

  适配类(Adaptee)

  定义一个接口,Adapter需要接入。即系统中原有的类,需要适配使之可以利用。

  客户端(Client)

  协同对象符合Adapter适配器。

 

适配器的分类

  适配器模式(Adapter Pattern)主要分为三种:

  1.基于类的继承方式,也称类适配器。

  2.基于对象组合方式,也称对象适配器,推荐这种实现而不是上一种使用继承

  3.缺省的适配器模式(AWT, Swing事件模型所采用的适配器模式)。

 

代码示例

  1.基于继承的:

复制代码
package com.meng.designpattern.adapter;

public interface Target
{
    public void method1();

}
复制代码
复制代码
package com.meng.designpattern.adapter;

//需要被适配的对象
public class Adaptee
{
    public void method2()
    {
        System.out.println("目标方法");
    }

}
复制代码
复制代码
package com.meng.designpattern.adapter;

public class Adapter extends Adaptee implements Target
{
    // 通过继承的方式来实现适配

    @Override
    public void method1()
    {
        this.method2();// 将method2适配成了method1
        // 即,通过method1来间接地调用method2
    }

}
复制代码

  使用的时候:

复制代码
package com.meng.designpattern.adapter;

public class Client
{
    public static void main(String[] args)
    {
        Target target = new Adapter();
        target.method1();// 通过method1来间接访问method2

    }

}
复制代码

 

 2.基于对象组合的:

 

复制代码
package com.meng.designpattern.adapter2;

public interface Target
{
    public void method1();

}
复制代码
复制代码
package com.meng.designpattern.adapter2;

public class Adaptee
{
    public void method2()
    {
        System.out.println("执行方法");
    }

}
复制代码
复制代码
package com.meng.designpattern.adapter2;

public class Adapter implements Target
{
    // 采取对象组合的方式实现适配器
    private Adaptee adaptee;

    public Adapter(Adaptee adaptee)
    {
        this.adaptee = adaptee;
    }

    @Override
    public void method1()
    {
        adaptee.method2();

    }

}
复制代码

  使用的时候:

复制代码
package com.meng.designpattern.adapter2;

public class Client
{
    public static void main(String[] args)
    {
        Target target = new Adapter(new Adaptee());
        target.method1();
    }

}
复制代码

 

3.AWT和Swing中使用的适配器模式:

  其目的就是为了避免在继承一个接口的时候要实现其中的所有方法,采用一个中间类(适配器类),这个类实现了接口中的所有方法,都是空实现。

  然后再继承这个适配器类时,自然也实现了目标接口。

  但是使用时不需要对接口其中的所有方法提供实现,只实现自己感兴趣的方法即可。

  这里也提供一个代码示例:

  首先是接口:

复制代码
package com.meng.designpattern.defaultadapter;

public interface AbstractService
{
    public void service1();
    
    public void service2();
    
    public void service3();

}
复制代码

  然后是适配器类:

复制代码
package com.meng.designpattern.defaultadapter;

public class ServiceAdapter implements AbstractService
{
    // 适配器中的所有方法都是空实现

    @Override
    public void service1()
    {

    }

    @Override
    public void service2()
    {

    }

    @Override
    public void service3()
    {

    }

}
复制代码

  实际使用的类:

复制代码
package com.meng.designpattern.defaultadapter;

public class ConcreteService extends ServiceAdapter
{
    // 继承适配器类而不是实现接口,这样就不用把接口中的所有方法都写一遍
    // 只覆写感兴趣的方法
    @Override
    public void service1()
    {
        System.out.println("service1执行");
    }

}
复制代码

 

 

适配器(Adapter)模式的适用性

  对象需要利用现存的并且接口不兼容的类。

  需要创建可重用的类以协调其他接口可能不兼容的类。

 

JUnit中的适配器模式

  JUnit3.8的TestCase的源代码中:

  

复制代码
    /**
     * Runs the bare test sequence.
     * @exception Throwable if any exception is thrown
     */
    public void runBare() throws Throwable {
        setUp();
        try {
            runTest();
        }
        finally {
            tearDown();
        }
    }    
复制代码

 

  runTest()中执行我们的测试方法。

  测试方法testXXX要求必须是public void并且不带参数的,这里就使用了适配器模式

  runTest()的实现如下:

复制代码
/**
     * Override to run the test and assert its state.
     * @exception Throwable if any exception is thrown
     */
    protected void runTest() throws Throwable {
        assertNotNull(fName);
        Method runMethod= null;
        try {
            // use getMethod to get all public inherited
            // methods. getDeclaredMethods returns all
            // methods of this class but excludes the
            // inherited ones.
            runMethod= getClass().getMethod(fName, null);
        } catch (NoSuchMethodException e) {
            fail("Method \""+fName+"\" not found");
        }
        if (!Modifier.isPublic(runMethod.getModifiers())) {
            fail("Method \""+fName+"\" should be public");
        }

        try {
            runMethod.invoke(this, new Class[0]);
        }
        catch (InvocationTargetException e) {
            e.fillInStackTrace();
            throw e.getTargetException();
        }
        catch (IllegalAccessException e) {
            e.fillInStackTrace();
            throw e;
        }
    }
复制代码

 

参考资料

  圣思园张龙老师视频教程。

 

posted @ 2015-08-22 09:38  凡尘里的一根葱  阅读(233)  评论(0编辑  收藏  举报