【设计模式】聊聊模板模式

原理和实现

设计模式的原理和实现是比较简单的,难的是掌握具体的应用场景和解决什么问题。而模板模式是为来解决复用和拓展两个问题。

模板模式在一个方法中定义好一个算法框架,然后将某些步骤推迟到子类中实现,子类可以在不修改父类流程的时候,实现自己的特有逻辑。

具体code如下。ZkLock定义顶层接口设计,ZkAbstractTemplateLock 实现了基础功能,但是具体的wait和try的流程是固定在ZKlock抽象类中,子类只能根据自己的特性实现对应的方法。

java 复制代码
public interface ZkLock {
    /***
     * 获取锁
     */
    public void zkLock();

    /***
     * 释放锁
     */
    public void zkUnLock();

}


public abstract class ZkAbstractTemplateLock implements ZkLock {

    private static final String ZKSERVER = "192.168.58.138:2181";
    private static final int TIME_OUT = 45 * 100;

    public static final String zkLockPath = "/zkLock";
    public static CountDownLatch countDownLatch = null;

    ZkClient zkClient =  new ZkClient(ZKSERVER,TIME_OUT);

    @Override
    public void zkLock() {
        //模板设计方法 抽象定义在父类中,具体实现由子类来实现
        if (tryLock()){
            System.out.println(Thread.currentThread().getName()+"\t 拿到锁");
        }else {
            waitLock();
            zkLock();
        }
    }

    //将公共的代码抽取到父类中
    public abstract void waitLock();

    /***
     * 尝试获取锁
     * @return
     */
    public abstract boolean tryLock();

    @Override
    public void zkUnLock() {
        if(zkClient!=null){
            zkClient.close();//关闭客户端 node节点自动删除
        }
        System.out.println(Thread.currentThread().getName()+"\t 释放锁成功");
        System.out.println();
    }
}


public class ZkDistributedLock extends ZkAbstractTemplateLock {

    @Override
    public void waitLock() {
        IZkDataListener iZkDataListener = new IZkDataListener() {
            @Override
            public void handleDataChange(String s, Object o) throws Exception {
            }

            //数据被修改 监听Watch
            @Override
            public void handleDataDeleted(String s) throws Exception {
                //如果节点数据删除了 那么countDownLatch减一
                countDownLatch.countDown();
            }
        };

        //在某一个节点上监听事件
        zkClient.subscribeDataChanges(zkLockPath,iZkDataListener);

        //当不为null
        if (zkClient.exists(zkLockPath)){
            countDownLatch = new CountDownLatch(1);//计数1 为0返回
            try {
                //一旦节点被删除 触发事件就执行
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.fillInStackTrace();
            }
        }
        //解除监听器
        zkClient.unsubscribeDataChanges(zkLockPath,iZkDataListener);
    }

    @Override
    public boolean tryLock() {
        try {
            zkClient.createEphemeral(zkLockPath);
            return true;
        }catch (Exception e){
            return false;
        }

    }
}

复用

java inputstream

inputstream 定义了read的基础读取方法,但是也暴露了一个子类可以定制的抽象方法。

java 复制代码
public abstract class InputStream implements Closeable {
    public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }

    public abstract int read() throws IOException;

}

java abstractList

abstract class AbstractList 定义了addAll() , 但是留除了一个拓展点给子类,如果子类不实现的话,不能使用。

java 复制代码
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        boolean modified = false;
        for (E e : c) {
            add(index++, e);
            modified = true;
        }
        return modified;
    }
    	
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

    //arraylist实现了自己的 add
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

拓展

java servlet

拓展点这里其实是指框架的拓展点,即用户在不修改框架源码的时候,只需要按照框架提高的类进行拓展就可以实现自己的业务逻辑。

小结

模板模式的本质定义一个框架流程,具体的拓展点可以子类进行实现。具体的功能是复用和拓展,复用是指的是,所有的子类可以复用父类中提供的模板方法的代码,拓展是框架通过模板模式提供功能拓展点,用户不修改框架源码的情况下,基于拓展点就可以实现功能。

相关推荐
晓13132 分钟前
第七章 【C语言篇:文件】 文件全面解析
linux·c语言·开发语言
愚者游世2 分钟前
Delegating Constructor(委托构造函数)各版本异同
开发语言·c++·程序人生·面试·改行学it
一 乐3 分钟前
校园二手交易|基于springboot + vue校园二手交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
KIKIiiiiiiii4 分钟前
微信个人号API二次开发中的解决经验
java·人工智能·python·微信
梵刹古音5 分钟前
【C语言】 指针基础与定义
c语言·开发语言·算法
80530单词突击赢5 分钟前
SpringBoot整合SpringMVC全解析
java·spring boot·后端
Ekehlaft8 分钟前
这款国产 AI,让 Python 小白也能玩转编程
开发语言·人工智能·python·ai·aipy
rit843249910 分钟前
MATLAB中Teager能量算子提取与解调信号的实现
开发语言·matlab
开源技术13 分钟前
Python GeoPandas基础知识:地图、投影和空间连接
开发语言·ide·python
vx1_Biye_Design15 分钟前
基于Spring Boot+Vue的学生管理系统设计与实现-计算机毕业设计源码46223
java·vue.js·spring boot·spring·eclipse·tomcat·maven