设计模式|适配器模式|开源项目加深理解

设计模式|适配器模式|开源项目加深理解

“设计模式参见”系列模式讲解,初学同学可参考观看,方便入门,本篇主要对开源项目中相关设计模式的实际应用做分析,加深同学们在实际应用中对相关模式的理解。

一家之言,欢迎大家指正!原创不易,转载请注明出处,感谢!
文章链接:https://editor.csdn.net/md/?articleId=105540394

适配器模式

分类
类适配器模式
对象适配器模式
接口适配器模式(非权威博文见,正确性待确认,单开说)
类与对象适配器模式

挂羊头,卖狗肉,顾客要羊,不要狗。

但是,顾客的目的只是拿到肉,而不会去管是”狗肉“还是”羊肉“。

怎么将“狗肉”挂到“羊头”底下,就是适配器需要干的事情。

区别:

类适配器模式:适配器对象通过继承”狗肉“(被适配者)对象,将”羊头“(目标对象)与”狗肉“适配,顾客看到是”羊头“,然后去拿到肉。

对象适配器模式:适配器对象将”狗肉“(被适配者)对象定义到自身内部,然后将”羊头“(目标对象)与”狗肉“适配,顾客看到是”羊头“,然后去拿到肉。

uml图例:

图 1. 适éå™¨æ¨¡å¼ç±

开源项目示例1

JDK1.1之前的集合(collection)类型(如:Vector、Stack、Hashtable)都实现了一个elements的方法,该方法会返回一个Enumeration类型对象:

interface Enumeration{
    hasMoreElements();//集合中是否还有更多元素
    nextElement();//拿集合的下一个元素
}

JDK1.2时,Sun退出更新后的集合类,开始使用Iterator(迭代器)接口:

interface Iterator{
    hasNext();//可取代hasMoreElements()
    next();//可取代nextElement()
    remove();
}

这俩接口功能很相似,不同的是Iterator还多提供了一个remove()方法,当我们面临1.1的遗留代码时,这些代码暴露出Enumeration接口,但是我们在1.2版本中只希望使用Iterator,面对这个问题,我们需要构造适配器。

接着我们对照着上面的uml图例,此时的目标接口即为:Iterator接口(羊头),此时的被适配者接口即为:Enumeration(狗头),此时构造我们的适配器要实现目标接口,hasNext()、next()很好实现,直接对应过去就好,remove()接口如何实现呢?

因为Enumeration(枚举)不支持删除,该接口即为”只读“接口,适配器无法实现一个有实际功能的remove()方法,最多抛出一个运行时异常,比较屌的是,迭代器接口设计者事先就考虑到了这种需要,所以把remove()方法定义为:

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

小试牛刀搞一下?同学们可以自己写一个EnumeratorIterator适配器,试试?

开源项目示例2

大家应该都知道Arrays.asList()这个方法,作用是将数组转为List集合。接下来我们展开讲讲,这个是怎么应用适配器模式的。

先看看Arrays.asList长啥样:

public class Arrays {
	//...
	public static <T> List<T> asList(T... a) {
       	 return new ArrayList<>(a);     
      /**将数组转为一个ArrayList集合,此处的ArrayList是作为一个内部类出现的,和			*java.util.ArrayList相比有哪些不同
        * 1、注意下构造函数,看看有哪些不同
        * 2、注意下复写的方法,看看少了那些
    	*/
    }
    
    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;  //狗肉出现了

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }

       //...
    }
    
}

和上面一样,我们照着uml图例一起往下分析

将数组转为List集合
1、顾客要使用集合;
2、我们实际有的是一个数组;
3、我们要做适配,将数组是配成集合供顾客使用
所以我们清楚了一件事:羊头即为:List   狗肉即为:数组[] 
然后我们看看适配的过程是怎么完成的

这个适配的过程其实是在Arrays类里面的内部类ArrayList的里面实现的,通过将数组对象定义在适配器里面 private final E[] a;去完成相应的适配过程,这种方式也就是我们上面提到的对象是配方式。

我们通过比较Arrays内部实现的ArrayList里面复写的方法,发现少了几个remove、add、clear等等,这也就是为什么在使用asList转换得到的集合,如果调用以上的三个方法会抛异常(UnsupportedOperationException),大家可以自己点开源码往下看看为什么。

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
	public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     *
     * 

This implementation always throws an * {@code UnsupportedOperationException}. * * @throws UnsupportedOperationException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { throw new UnsupportedOperationException(); } }

你可能感兴趣的:(设计模式)