原理和实现
设计模式的原理和实现是比较简单的,难的是掌握具体的应用场景和解决什么问题。而模板模式是为来解决复用和拓展两个问题。
模板模式在一个方法中定义好一个算法框架,然后将某些步骤推迟到子类中实现,子类可以在不修改父类流程的时候,实现自己的特有逻辑。
具体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
拓展点这里其实是指框架的拓展点,即用户在不修改框架源码的时候,只需要按照框架提高的类进行拓展就可以实现自己的业务逻辑。
小结
模板模式的本质定义一个框架流程,具体的拓展点可以子类进行实现。具体的功能是复用和拓展,复用是指的是,所有的子类可以复用父类中提供的模板方法的代码,拓展是框架通过模板模式提供功能拓展点,用户不修改框架源码的情况下,基于拓展点就可以实现功能。