欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java设计模式——适配器模式(Adapter)

程序员文章站 2022-03-29 19:49:18
目的:把源类型适配为目标类型,以适应客户端(Client)的需求;此处我们把目标接口的调用方视为客户端 使用场景:需要对类型进行由源类型到目标类型转换的场景中 前置条件:已有客户端 常用的几种模式 模式一:存在目标接口,且存在已有方法 我们假设ExistClass返回的字符串正好是我们的客户端需要用 ......

目的:把源类型适配为目标类型,以适应客户端(client)的需求;此处我们把目标接口的调用方视为客户端

使用场景:需要对类型进行由源类型到目标类型转换的场景中

前置条件已有客户端

//client 一个调用目标接口的方法
class clientinvoking {

    static void invoke(targetinterface target) {
        string value = target.getmark();
        system.out.println(value);
    }

}

常用的几种模式

模式一:存在目标接口,且存在已有方法

//目标接口
public interface targetinterface {
    
    public string getmark();

    public string getinfo();

}
//已有类及方法
public class existclass {

    public string sayhello() {
        return "hello";
    }
      
    public string sayworld() {
        return "world";
    }
}

我们假设existclass返回的字符串正好是我们的客户端需要用到的,但客户端需要的是通过一个targetinterface类型的对象来获取,因此我们需要想办法对已有类进行适配,使其能够满足客户端的需求;该模式下存在两种应用方案:

方案1.类适配器模式

//适配器
public class classadapter extends existclass implements targetinterface {
    
    public int getmark() {
        string value = this.sayhello();
        return value;
    }
    
    public int getinfo() {
        string value = this.sayworld();
        return value;
    }
    
}
//客户端调用
targetinterface target = new classadapter();
clientinvoking.invoke(target);

由java接口的概念可知,classadapter作为targetinterface的实现类,能够向上转型为targetinterface类型,适应了客户端的需求。

方案2.对象适配器模式

//适配器
public class classadapter implements targetinterface {
    
    private existclass exist;
    
    public classadapter(existclass existclass) {
        this.exist = existclass;
    }
    
    public int getmark() {
        string value = exist.sayhello();
        return value;
    }
    
    public int getinfo() {
        string value = exist.sayworld();
        return value;
    }
    
}
//客户端调用
targetinterface target = new classadapter(new existclass());
clientinvoking.invoke(target);

该方案与类适配器模式类似,只是不采用继承而采用持有对象的方式,更加灵活,扩展性更强。

模式二:不存在目标接口,但是存在目标类,且存在已有方法

我们先对前置条件中的客户端进行改造,如下:

class clientinvoking {

    static void invoke(targetclass target) {
        string value = target.getmark();
        system.out.println(value);
    }

}

改造后,invoke方法需要一个targetclass类的对象作为参数;下面是目标类和已有类

//目标类
public class class {
    
    public string getmark() {
        return "yes";
    }

    public string getinfo() {
        return "no";
    }

}
//已有类及方法
public class existclass {

    public string sayhello() {
        return "hello";
    }
      
    public string sayworld() {
        return "world";
    }
}

我们假设existclass返回的字符串正好是我们的客户端需要用到的,且客户端中需要的targetclass对象的内容已经过时,因此我们需要相办法对existclass进行适配,以适应客户端的需求;

//适配器
public class classadapter extends targetclass {
    
    private existclass exist;
    
    public classadapter(existclass existclass) {
        this.exist = existclass;
    }
    
    public int getmark() {
        string value = exist.sayhello();
        return value;
    }
    
    public int getinfo() {
        string value = exist.sayworld();
        return value;
    }
    
}
//客户端调用
targetclass target = new classadapter(new existclass());
clientinvoking.invoke(target);

在该种模式下,设计到两个类,且最后要进行向上转型,根据java的单继承机制,我们只能通过持有对象的形式,即对象适配器模式。

模式三:缺省适配器模式

该模式中,不存在显式的目标类型,而仅有源类型;之所以需要用到这个,往往是因为源类型中提供了太多我们并不需要的东西,我们需要通过适配器模式进行定制化。以windowlistener作为例子讲解:

//windowlistener源码
public interface windowlistener extends eventlistener {
    public void windowopened(windowevent e);
    public void windowclosing(windowevent e);
    public void windowclosed(windowevent e);
    ...
}
//添加监听器的例子
frame frame = new frame();
frame.addwindowlistener(new windowlistener() {
    @override
    public void windowopened(windowevent e) {
            
    }

    @override
    public void windowclosing(windowevent e) {

    }

    @override
    public void windowclosed(windowevent e) {

    }
    ...
})

这样的代码,看起来很繁琐;比如说我只需要监听正在关闭的事件,却生成了许多与此无关的模板代码,降低了代码的可读性,鉴于此,我们来做下定制,只监听一个接口;

我们首先提供一个抽象类实现了该接口,并为所有监听器提供空实现;然后再用抽象类的子类重写窗口正在关闭的监听器的实现,代码如下:

//适配器
public abstract listeneradapter implements windowlistener {
    public void windowopened(windowevent e) {}
    public void windowclosing(windowevent e) {}
    public void windowclosed(windowevent e) {}
    ...
}
//重写方法
public class overridewindowclosing extends listeneradapter {
    
    @override
    public void windowclosing(windowevent e) {
        //todo
    }
    
}
//客户端调用
frame.addwindowlistener(new overridewindowclosing());

该方式简化了接口,提高了代码可读性。最重要的是,我们实现了对接口的定制,可以只做自己关心的事情。