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

原理和实现

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

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

具体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

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

小结

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

相关推荐
Dola_Pan29 分钟前
Linux文件IO(二)-文件操作使用详解
java·linux·服务器
wang_book31 分钟前
Gitlab学习(007 gitlab项目操作)
java·运维·git·学习·spring·gitlab
AI原吾1 小时前
掌握Python-uinput:打造你的输入设备控制大师
开发语言·python·apython-uinput
机器视觉知识推荐、就业指导1 小时前
Qt/C++事件过滤器与控件响应重写的使用、场景的不同
开发语言·数据库·c++·qt
毕设木哥1 小时前
25届计算机专业毕设选题推荐-基于python的二手电子设备交易平台【源码+文档+讲解】
开发语言·python·计算机·django·毕业设计·课程设计·毕设
珞瑜·1 小时前
Matlab R2024B软件安装教程
开发语言·matlab
weixin_455446171 小时前
Python学习的主要知识框架
开发语言·python·学习
孤寂大仙v1 小时前
【C++】STL----list常见用法
开发语言·c++·list
蜗牛^^O^1 小时前
Docker和K8S
java·docker·kubernetes
她似晚风般温柔7892 小时前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app