简介
结构型设计模式
结构型设计模式描述如何将类和对象结合在一起形成更大的结构。
分类:类结构型和对象结构型
- 类结构型关心得是类的组合,由多个类组合成一个更大的系统,在类结构中一般存在继承和实现关系。
- 对象结构型关心得是类和对象得组合,通过在一个类中定义另一个类得实例得方式将它们关联起来。一般用关联关系来代替继承,所以大多数结构型模式都是对象结构型。
适配器模式
今天要讲得适配器模式就是结构型设计模式的一种。
定义:将一个接口转化为客户希望的另一个接口,使得接口不兼容的类可以一起工作。
说明:在适配器模式中需要定义一个包装类,包装不兼容接口的对象,这个包装类就是适配器,被包装的就是适配者。
模式动机:将客户的请求转化为适配者的相应接口的调用。也就是说:在客户类调用适配器的方法时,适配器将会在内部调用适配者的方法,这个过程对客户类来说是透明的,客户类并不直接访问适配者的方法。
根据结构可以分为类适配器和对象适配:
类适配器:
对象适配器:
模式结构说明:
Target:用户所期望的接口,可以是抽象类也可以是一个接口。
Adapter:适配器类对Adaptee和Target的进行适配,是适配器模式的核心。
Adaptee:适配者类,即被适配的类。
Client:客户端
类适配器模式
首先是目标类(或接口)Target
public interface Target {
void request();
}
适配者类Adaptee
public class Adaptee {
public void adapteeRequest() {
System.out.println("被适配类的方法。。。");
}
}
类适配器
public class Adapter extends Adaptee implements Target {
@Override
public void request() {
super.adapteeRequest();
}
}
public class Test {
public static void main(String[] args) {
Target t = new Adapter();
t.request();
}
}
//输出:被适配类的方法。。。
对象适配器
目标类和适配者类是不变的,主要是适配器类结构的改变
对象适配器:
public class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.adapteeRequest();
}
}
测试:
public class Test {
public static void main(String[] args) {
Target t = new ObjectAdapter(new Adaptee());
t.request();
}
}
//结果:被适配类的方法。。。
缺省适配器模式
上面说到的情况都是很简单的,适配者类仅有很少的方法,而且都是有用的。假如现在有一个适配者接口:
interface NewAdaptee {
void sing();
void dance();
void rap();
void basketball();
void run();
}
存在有很多的方法,而且都没有实现。如果我们使用上面的类适配器模式的话就需要实现全部的方法。但是我现在的新目标接口是这样的:
interface NewTarget {
void singer();
}
我只对sing感兴趣,那么就多做了很多不必要的工作。这个时候就引入了缺省适配器的概念,用一个抽象类实现该目标接口,为每一个方法提供默认实现(空方法)。也可以有选择的实现一些方法,根据具体的业务考虑。具体的适配器则继承这个抽象类来实现目标接口。
缺省适配器:
abstract class DefultAdapter implements NewAdaptee {
public void sing() {}
public void dance() {}
public void rap() {}
public void basketball() {}
public void run() {}
}
具体适配器:
class SpecificAdapter extends DefultAdapter implements NewTarget {
public void sing() {
System.out.println("我会唱歌。。。");
}
public void singer() {
this.sing();
}
}
测试:
public class Test {
public static void main(String[] args) {
NewTarget t = new SpecificAdapter();
t.singer();
}
}
//输出:我会唱歌。。。
在JDK类库的java.awt.event中广泛使用了缺省适配器模式,比如WindowAdapter、KeyAdapter等
我们来看WindowListener:
public interface WindowListener extends EventListener {
public void windowOpened(WindowEvent e);
public void windowClosing(WindowEvent e);
public void windowClosed(WindowEvent e);
public void windowIconified(WindowEvent e);
public void windowDeiconified(WindowEvent e);
public void windowActivated(WindowEvent e);
public void windowDeactivated(WindowEvent e);
}
如果直接使用实现该接口的方式,就不得不处理一些其他的用不到的方法。而使用缺省的适配器WindowAdapter就方便多了
WindowAdapter:
public abstract class WindowAdapter
implements WindowListener, WindowStateListener, WindowFocusListener
{
public void windowOpened(WindowEvent e) {}
public void windowClosing(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowStateChanged(WindowEvent e) {}
public void windowLostFocus(WindowEvent e) {}
}
通过继承缺省适配器的方式只需要实现自己感兴趣的方法即可。
优缺点比较
首先说适配器本身具有的优点:
- 将目标类和适配者类解耦
- 增加了类的透明性和复用性。客户端看不到适配者类接口转换为目标接口的过程,对客户端来说是透明的。
- 灵活性和扩展性好。可以更换适配器来完成不同的需求
对于类适配器来说:
- 优点:可以重写适配者类的一些方法,更加灵活
- 缺点:对于单继承的语言,如java,具有一定局限
对于对象适配器来说:
- 优点:可以适配多个适配者
- 缺点:如果要重写适配者的一些方法过程就比较复杂了,先要作一个适配者类的子类,然后修改方法。适配器去适配这个子类才可以,过程比较复杂。
适用场景
- 系统要使用一些现有的类,但是这些类的接口不满足需要。
- 建立一个可重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。(就是用适配器去适配不同的类接口)
那适配器模式就到这里了,讲的干巴巴的,以后用尝试新的方式帮助大家理解和记忆。
文章的不足和错误,欢迎大家留言指出!