适配器应用广泛,比如我去马代看海就得带着适配器去,要不然手机就没法充电了。因为人家电压是240伏,插座是三孔方形的,需要一个转换器变成220伏,这时才可以使用插入两脚的充电插头。这个转换器就是适配器,很明显,适配器的作用就是负责兼容A和B两种原来不能直接互相交互的接口。适配器模式也是同样的道理,当A接口不能直接调用B接口时,我们通过适配器模式来转换一下。看个具体例子:
我们把Window当做马代的插座,那么WindowListener的windowClosing方法我们需要用到的两脚插口,而WindowAdapter就是插座转换器,只不过这里转换的实际操作由它的子类FrameListener做了,它通过引入DragWindow(实际上还有其他对象)实现具体逻辑。当然WindowListener接口最终是给使用它的手机调用的。
看下代码:
1、WindowListener
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. package java.awt.event; import java.util.EventListener; /** * The listener interface for receiving window events. * The class that is interested in processing a window event * either implements this interface (and all the methods it * contains) or extends the abstract <code>WindowAdapter</code> class * (overriding only the methods of interest). * The listener object created from that class is then registered with a * Window using the window's <code>addWindowListener</code> * method. When the window's status changes by virtue of being opened, * closed, activated or deactivated, iconified or deiconified, * the relevant method in the listener object is invoked, and the * <code>WindowEvent</code> is passed to it. * * @author Carl Quinn * * @see WindowAdapter * @see WindowEvent * @see <a href="https://docs.oracle.com/javase/tutorial/uiswing/events/windowlistener.html">Tutorial: How to Write Window Listeners</a> * * @since 1.1 */ public interface WindowListener extends EventListener { /** * Invoked the first time a window is made visible. */ public void windowOpened(WindowEvent e); /** * Invoked when the user attempts to close the window * from the window's system menu. */ public void windowClosing(WindowEvent e); /** * Invoked when a window has been closed as the result * of calling dispose on the window. */ public void windowClosed(WindowEvent e); /** * Invoked when a window is changed from a normal to a * minimized state. For many platforms, a minimized window * is displayed as the icon specified in the window's * iconImage property. * @see java.awt.Frame#setIconImage */ public void windowIconified(WindowEvent e); /** * Invoked when a window is changed from a minimized * to a normal state. */ public void windowDeiconified(WindowEvent e); /** * Invoked when the Window is set to be the active Window. Only a Frame or * a Dialog can be the active Window. The native windowing system may * denote the active Window or its children with special decorations, such * as a highlighted title bar. The active Window is always either the * focused Window, or the first Frame or Dialog that is an owner of the * focused Window. */ public void windowActivated(WindowEvent e); /** * Invoked when a Window is no longer the active Window. Only a Frame or a * Dialog can be the active Window. The native windowing system may denote * the active Window or its children with special decorations, such as a * highlighted title bar. The active Window is always either the focused * Window, or the first Frame or Dialog that is an owner of the focused * Window. */ public void windowDeactivated(WindowEvent e); }
2、WindowAdapter
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. package java.awt.event; /** * An abstract adapter class for receiving window events. * The methods in this class are empty. This class exists as * convenience for creating listener objects. * <P> * Extend this class to create a <code>WindowEvent</code> listener * and override the methods for the events of interest. (If you implement the * <code>WindowListener</code> 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 Window using the window's <code>addWindowListener</code> * method. When the window's status changes by virtue of being opened, * closed, activated or deactivated, iconified or deiconified, * the relevant method in the listener * object is invoked, and the <code>WindowEvent</code> is passed to it. * * @see WindowEvent * @see WindowListener * @see <a href="https://docs.oracle.com/javase/tutorial/uiswing/events/windowlistener.html">Tutorial: Writing a Window Listener</a> * * @author Carl Quinn * @author Amy Fowler * @author David Mendenhall * @since 1.1 */ public abstract class WindowAdapter implements WindowListener, WindowStateListener, WindowFocusListener { /** * Invoked when a window has been opened. */ public void windowOpened(WindowEvent e) {} /** * Invoked when a window is in the process of being closed. * The close operation can be overridden at this point. */ public void windowClosing(WindowEvent e) {} /** * Invoked when a window has been closed. */ public void windowClosed(WindowEvent e) {} /** * Invoked when a window is iconified. */ public void windowIconified(WindowEvent e) {} /** * Invoked when a window is de-iconified. */ public void windowDeiconified(WindowEvent e) {} /** * Invoked when a window is activated. */ public void windowActivated(WindowEvent e) {} /** * Invoked when a window is de-activated. */ public void windowDeactivated(WindowEvent e) {} /** * Invoked when a window state is changed. * @since 1.4 */ public void windowStateChanged(WindowEvent e) {} /** * Invoked when the Window is set to be the focused Window, which means * that the Window, or one of its subcomponents, will receive keyboard * events. * * @since 1.4 */ public void windowGainedFocus(WindowEvent e) {} /** * Invoked when the Window is no longer the focused Window, which means * that keyboard events will no longer be delivered to the Window or any of * its subcomponents. * * @since 1.4 */ public void windowLostFocus(WindowEvent e) {} }
3、FrameListener(BasicToolBarUI的内部类)
protected class FrameListener extends WindowAdapter { public void windowClosing(WindowEvent w) { if (toolBar.isFloatable()) { if (dragWindow != null) dragWindow.setVisible(false); floating = false; if (floatingToolBar == null) floatingToolBar = createFloatingWindow(toolBar); if (floatingToolBar instanceof Window) ((Window)floatingToolBar).setVisible(false); floatingToolBar.getContentPane().remove(toolBar); String constraint = constraintBeforeFloating; if (toolBar.getOrientation() == JToolBar.HORIZONTAL) { if (constraint == "West" || constraint == "East") { constraint = "North"; } } else { if (constraint == "North" || constraint == "South") { constraint = "West"; } } if (dockingSource == null) dockingSource = toolBar.getParent(); if (propertyListener != null) UIManager.removePropertyChangeListener(propertyListener); dockingSource.add(toolBar, constraint); dockingSource.invalidate(); Container dockingSourceParent = dockingSource.getParent(); if (dockingSourceParent != null) dockingSourceParent.validate(); dockingSource.repaint(); } } }
4、DragWindow
protected class DragWindow extends Window { Color borderColor = Color.gray; int orientation = toolBar.getOrientation(); Point offset; // offset of the mouse cursor inside the DragWindow DragWindow(Window w) { super(w); } /** * Returns the orientation of the toolbar window when the toolbar is * floating. The orientation is either one of <code>JToolBar.HORIZONTAL</code> * or <code>JToolBar.VERTICAL</code>. * * @return the orientation of the toolbar window * @since 1.6 */ public int getOrientation() { return orientation; } public void setOrientation(int o) { if(isShowing()) { if (o == this.orientation) return; this.orientation = o; Dimension size = getSize(); setSize(new Dimension(size.height, size.width)); if (offset!=null) { if( BasicGraphicsUtils.isLeftToRight(toolBar) ) { setOffset(new Point(offset.y, offset.x)); } else if( o == JToolBar.HORIZONTAL ) { setOffset(new Point( size.height-offset.y, offset.x)); } else { setOffset(new Point(offset.y, size.width-offset.x)); } } repaint(); } } public Point getOffset() { return offset; } public void setOffset(Point p) { this.offset = p; } public void setBorderColor(Color c) { if (this.borderColor == c) return; this.borderColor = c; repaint(); } public Color getBorderColor() { return this.borderColor; } public void paint(Graphics g) { paintDragWindow(g); // Paint the children super.paint(g); } public Insets getInsets() { return new Insets(1,1,1,1); } }
5、Window
public class Window extends Container implements Accessible { /** * Shows or hides this {@code Window} depending on the value of parameter * {@code b}. * <p> * If the method shows the window then the window is also made * focused under the following conditions: * <ul> * <li> The {@code Window} meets the requirements outlined in the * {@link #isFocusableWindow} method. * <li> The {@code Window}'s {@code autoRequestFocus} property is of the {@code true} value. * <li> Native windowing system allows the {@code Window} to get focused. * </ul> * There is an exception for the second condition (the value of the * {@code autoRequestFocus} property). The property is not taken into account if the * window is a modal dialog, which blocks the currently focused window. * <p> * Developers must never assume that the window is the focused or active window * until it receives a WINDOW_GAINED_FOCUS or WINDOW_ACTIVATED event. * @param b if {@code true}, makes the {@code Window} visible, * otherwise hides the {@code Window}. * If the {@code Window} and/or its owner * are not yet displayable, both are made displayable. The * {@code Window} will be validated prior to being made visible. * If the {@code Window} is already visible, this will bring the * {@code Window} to the front.<p> * If {@code false}, hides this {@code Window}, its subcomponents, and all * of its owned children. * The {@code Window} and its subcomponents can be made visible again * with a call to {@code #setVisible(true)}. * @see java.awt.Component#isDisplayable * @see java.awt.Component#setVisible * @see java.awt.Window#toFront * @see java.awt.Window#dispose * @see java.awt.Window#setAutoRequestFocus * @see java.awt.Window#isFocusableWindow */ public void setVisible(boolean b) { super.setVisible(b); } }
我们从FrameListener看到,适配器引入了多个对象一起实现了windowClosing方法,被引入的Window对象实际上仅仅负责其中一部分逻辑。因此我们看到,适配器模式所适配的对象之间并无直接关联。接下来再看一个例子:
1、被适配的对象(A接口)
* Copyright (c) 1994, 2005, Oracle and/or its affiliates. All rights reserved. package java.util; /** * An object that implements the Enumeration interface generates a * series of elements, one at a time. Successive calls to the * <code>nextElement</code> method return successive elements of the * series. * <p> * For example, to print all elements of a <tt>Vector<E></tt> <i>v</i>: * <pre> * for (Enumeration<E> e = v.elements(); e.hasMoreElements();) * System.out.println(e.nextElement());</pre> * <p> * Methods are provided to enumerate through the elements of a * vector, the keys of a hashtable, and the values in a hashtable. * Enumerations are also used to specify the input streams to a * <code>SequenceInputStream</code>. * <p> * NOTE: The functionality of this interface is duplicated by the Iterator * interface. In addition, Iterator adds an optional remove operation, and * has shorter method names. New implementations should consider using * Iterator in preference to Enumeration. * * @see java.util.Iterator * @see java.io.SequenceInputStream * @see java.util.Enumeration#nextElement() * @see java.util.Hashtable * @see java.util.Hashtable#elements() * @see java.util.Hashtable#keys() * @see java.util.Vector * @see java.util.Vector#elements() * * @author Lee Boynton * @since JDK1.0 */ public interface Enumeration<E> { /** * Tests if this enumeration contains more elements. * * @return <code>true</code> if and only if this enumeration object * contains at least one more element to provide; * <code>false</code> otherwise. */ boolean hasMoreElements(); /** * Returns the next element of this enumeration if this enumeration * object has at least one more element to provide. * * @return the next element of this enumeration. * @exception NoSuchElementException if no more elements exist. */ E nextElement(); }
2、适配对象(B接口)
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. package java.util; import java.util.function.Consumer; /** * An iterator over a collection. {@code Iterator} takes the place of * {@link Enumeration} in the Java Collections Framework. Iterators * differ from enumerations in two ways: * * <ul> * <li> Iterators allow the caller to remove elements from the * underlying collection during the iteration with well-defined * semantics. * <li> Method names have been improved. * </ul> * * <p>This interface is a member of the * <a href="{@docRoot}/../technotes/guides/collections/index.html"> * Java Collections Framework</a>. * * @param <E> the type of elements returned by this iterator * * @author Josh Bloch * @see Collection * @see ListIterator * @see Iterable * @since 1.2 */ public interface Iterator<E> { /** * Returns {@code true} if the iteration has more elements. * (In other words, returns {@code true} if {@link #next} would * return an element rather than throwing an exception.) * * @return {@code true} if the iteration has more elements */ boolean hasNext(); /** * Returns the next element in the iteration. * * @return the next element in the iteration * @throws NoSuchElementException if the iteration has no more elements */ E next(); /** * Removes from the underlying collection the last element returned * by this iterator (optional operation). This method can be called * only once per call to {@link #next}. The behavior of an iterator * is unspecified if the underlying collection is modified while the * iteration is in progress in any way other than by calling this * method. * * @implSpec * The default implementation throws an instance of * {@link UnsupportedOperationException} and performs no other action. * * @throws UnsupportedOperationException if the {@code remove} * operation is not supported by this iterator * * @throws IllegalStateException if the {@code next} method has not * yet been called, or the {@code remove} method has already * been called after the last call to the {@code next} * method */ default void remove() { throw new UnsupportedOperationException("remove"); } /** * Performs the given action for each remaining element until all elements * have been processed or the action throws an exception. Actions are * performed in the order of iteration, if that order is specified. * Exceptions thrown by the action are relayed to the caller. * * @implSpec * <p>The default implementation behaves as if: * <pre>{@code * while (hasNext()) * action.accept(next()); * }</pre> * * @param action The action to be performed for each element * @throws NullPointerException if the specified action is null * @since 1.8 */ default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } }
3、适配器
* Licensed to the Apache Software Foundation (ASF) under one or more package org.apache.commons.collections.iterators; import java.util.Enumeration; import java.util.Iterator; /** * Adapter to make an {@link Iterator Iterator} instance appear to be * an {@link Enumeration Enumeration} instance. * * @since Commons Collections 1.0 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $ * * @author <a href="mailto:jstrachan@apache.org">James Strachan</a> */ public class IteratorEnumeration implements Enumeration { /** The iterator being decorated. */ private Iterator iterator; /** * Constructs a new <code>IteratorEnumeration</code> that will not * function until {@link #setIterator(Iterator) setIterator} is * invoked. */ public IteratorEnumeration() { super(); } /** * Constructs a new <code>IteratorEnumeration</code> that will use * the given iterator. * * @param iterator the iterator to use */ public IteratorEnumeration( Iterator iterator ) { super(); this.iterator = iterator; } // Iterator interface //------------------------------------------------------------------------- /** * Returns true if the underlying iterator has more elements. * * @return true if the underlying iterator has more elements */ public boolean hasMoreElements() { return iterator.hasNext(); } /** * Returns the next element from the underlying iterator. * * @return the next element from the underlying iterator. * @throws java.util.NoSuchElementException if the underlying iterator has no * more elements */ public Object nextElement() { return iterator.next(); } // Properties //------------------------------------------------------------------------- /** * Returns the underlying iterator. * * @return the underlying iterator */ public Iterator getIterator() { return iterator; } /** * Sets the underlying iterator. * * @param iterator the new underlying iterator */ public void setIterator( Iterator iterator ) { this.iterator = iterator; } }