为什么要有适配器模式?
系统在初期规划时设计了一个Target类,然后第三方提供了一个实现与Target功能的Adaptee类,但此时Target因为与系统其他部分都有联系,Adaptee已经设计好了,两者可能都不可修改了,此时为了调用Adaptee这一目的就需要通过一个Adapter来作为一个中介帮助。因为Adapter是Target的子类或者继承了他的接口,根据里氏代换原则,只需在
如何实现适配器模式?
类适配器
适配器继承需要通信的两个类,然后在目标类的方法中调用源类的方法,因为java是单继承的,所以目标类和源类一个是类一个是接口。
对象适配器
适配器类继承目标接口,然后在适配器类中持有源类的引用。
两者的区别是:因为java等语言是单继承的,所以对应类适配器,一个适配器只能给一个源类使用。对象适配器虽然可以将多个源Adaptee适配到同一个Target类但是她的缺点是,源类Adaptee各种方法深入Adatper类想要去掉一个很难全部找到,有时只能通过生成该Adaptee的子类然后重写它的方法,让Adapter持有这个子类来解决。不过对象适配器增加一个源类却是非常方便的。
UML类图
类适配器
对象适配器
代码示例
类适配器
package com.company; public interface Target{ void sampleOperation1(); void sampleOperation2(); }
package com.company; public class Adaptee { public void sampleOperation1(){}; }
package com.company; public class Adapter extends Adaptee implements Target{ @Override public void sampleOperation2() { //此方法为适配器类扩展Adaptee源类来满足目标接口 } }
对象适配器
Adaptee与Target和类适配器一样Adapter修改成
package com.company; public class Adapter implements Target{ private Adaptee adaptee; public Adapter(Adaptee adaptee){ super(); this.adaptee=adaptee; } @Override public void sampleOperation1() { adaptee.sampleOperation1(); } @Override public void sampleOperation2() { //此方法为适配器类扩展Adaptee源类来满足目标接口 } }
例题java jdk 1.0 1.1 没有聚集框架,因此访问集合等类时使用的是Enumeration,在jdk 1.2出现后Iterator接口成为了访问聚集框架的标准,但是为了兼容以前的版本我们需要各实现一个集合类来实现Iterator到Enumeration之间的互相转变。
Iterator To Enumeration
package com.company; import java.util.Enumeration; import java.util.Iterator; public class Itermeration implements Enumeration { private Iterator it; public Itermeration(Iterator it){ this.it=it; } @Override public boolean hasMoreElements() { return it.hasNext(); } @Override public Object nextElement() { return it.next(); } }
Enumeration To Iterator
因为Iterator接口中比Enumeration多remove和forEachRemaining两个函数,因此要在调用这两个函数的时候抛出异常
package com.company; import java.util.Enumeration; import java.util.Iterator; import java.util.function.Consumer; public class Enuterator implements Iterator { private Enumeration myEnum; public Enuterator(Enumeration myEnum) { this.myEnum=myEnum; } @Override public boolean hasNext() { return myEnum.hasMoreElements(); } @Override public Object next() { return myEnum.nextElement(); } public void remove(){ throw new UnsupportedOperationException(); } @Override public void forEachRemaining(Consumer action) { throw new UnsupportedOperationException(); } }
适配器模式在java中的应用
JDBC:不同的数据库是提供的接口是不同的,但是java操作SQL的方法是固定的,因此JDBC就是一个适配器的作用,来让java可以调用不同的数据库
AWT事件中各种个样的适配器:
注意这些适配器都是抽象类但是缺省实现了各种方法。
比如MouseAdapter
package java.awt.event; /** * An abstract adapter class for receiving mouse events. * The methods in this class are empty. This class exists as * convenience for creating listener objects. * <P> * Mouse events let you track when a mouse is pressed, released, clicked, * moved, dragged, when it enters a component, when it exits and * when a mouse wheel is moved. * <P> * Extend this class to create a {@code MouseEvent} * (including drag and motion events) or/and {@code MouseWheelEvent} * listener and override the methods for the events of interest. (If you implement the * {@code MouseListener}, * {@code MouseMotionListener} * interface, you have to define all of * the methods in it. This abstract class defines null methods for them * all, so you can only have to define methods for events you care about.) * <P> * Create a listener object using the extended class and then register it with * a component using the component's {@code addMouseListener} * {@code addMouseMotionListener}, {@code addMouseWheelListener} * methods. * The relevant method in the listener object is invoked and the {@code MouseEvent} * or {@code MouseWheelEvent} is passed to it in following cases: * <ul> * <li>when a mouse button is pressed, released, or clicked (pressed and released) * <li>when the mouse cursor enters or exits the component * <li>when the mouse wheel rotated, or mouse moved or dragged * </ul> * * @author Carl Quinn * @author Andrei Dmitriev * * @see MouseEvent * @see MouseWheelEvent * @see MouseListener * @see MouseMotionListener * @see MouseWheelListener * @see <a href="https://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html">Tutorial: Writing a Mouse Listener</a> * * @since 1.1 */ public abstract class MouseAdapter implements MouseListener, MouseWheelListener, MouseMotionListener { /** * {@inheritDoc} */ public void mouseClicked(MouseEvent e) {} /** * {@inheritDoc} */ public void mousePressed(MouseEvent e) {} /** * {@inheritDoc} */ public void mouseReleased(MouseEvent e) {} /** * {@inheritDoc} */ public void mouseEntered(MouseEvent e) {} /** * {@inheritDoc} */ public void mouseExited(MouseEvent e) {} /** * {@inheritDoc} * @since 1.6 */ public void mouseWheelMoved(MouseWheelEvent e){} /** * {@inheritDoc} * @since 1.6 */ public void mouseDragged(MouseEvent e){} /** * {@inheritDoc} * @since 1.6 */ public void mouseMoved(MouseEvent e){} }