原理和实现
设计模式的原理和实现是比较简单的,难的是掌握具体的应用场景和解决什么问题。而模板模式是为来解决复用和拓展两个问题。
模板模式在一个方法中定义好一个算法框架,然后将某些步骤推迟到子类中实现,子类可以在不修改父类流程的时候,实现自己的特有逻辑。
具体code如下。ZkLock定义顶层接口设计,ZkAbstractTemplateLock 实现了基础功能,但是具体的wait和try的流程是固定在ZKlock抽象类中,子类只能根据自己的特性实现对应的方法。
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);@Overridepublic void zkLock() {//模板设计方法 抽象定义在父类中,具体实现由子类来实现if (tryLock()){System.out.println(Thread.currentThread().getName()+"\t 拿到锁");}else {waitLock();zkLock();}}//将公共的代码抽取到父类中public abstract void waitLock();/**** 尝试获取锁* @return*/public abstract boolean tryLock();@Overridepublic void zkUnLock() {if(zkClient!=null){zkClient.close();//关闭客户端 node节点自动删除}System.out.println(Thread.currentThread().getName()+"\t 释放锁成功");System.out.println();}
}public class ZkDistributedLock extends ZkAbstractTemplateLock {@Overridepublic void waitLock() {IZkDataListener iZkDataListener = new IZkDataListener() {@Overridepublic void handleDataChange(String s, Object o) throws Exception {}//数据被修改 监听Watch@Overridepublic void handleDataDeleted(String s) throws Exception {//如果节点数据删除了 那么countDownLatch减一countDownLatch.countDown();}};//在某一个节点上监听事件zkClient.subscribeDataChanges(zkLockPath,iZkDataListener);//当不为nullif (zkClient.exists(zkLockPath)){countDownLatch = new CountDownLatch(1);//计数1 为0返回try {//一旦节点被删除 触发事件就执行countDownLatch.await();} catch (InterruptedException e) {e.fillInStackTrace();}}//解除监听器zkClient.unsubscribeDataChanges(zkLockPath,iZkDataListener);}@Overridepublic boolean tryLock() {try {zkClient.createEphemeral(zkLockPath);return true;}catch (Exception e){return false;}}
}
复用
java inputstream
inputstream 定义了read的基础读取方法,但是也暴露了一个子类可以定制的抽象方法。
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() , 但是留除了一个拓展点给子类,如果子类不实现的话,不能使用。
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实现了自己的 addpublic 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
拓展点这里其实是指框架的拓展点,即用户在不修改框架源码的时候,只需要按照框架提高的类进行拓展就可以实现自己的业务逻辑。
小结
模板模式的本质定义一个框架流程,具体的拓展点可以子类进行实现。具体的功能是复用和拓展,复用是指的是,所有的子类可以复用父类中提供的模板方法的代码,拓展是框架通过模板模式提供功能拓展点,用户不修改框架源码的情况下,基于拓展点就可以实现功能。