本来想学习spring源码的,但现在的水平去读它感觉太难了,还是先学习一些设计模式(毕竟开源框架中使用了很多的设计模式),在去深入理解它的机制。从简单的模板方法模式开始吧。
(一)什么是模板方法模式
一个操作中的算法框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构就可以定义该算法的某些特定步骤。有些抽象,等下举个例子会更明白。
(二)模板方法模式的使用:抽象类抽象子类共性+子类继承重写抽象方法
(三)模板方法模式的优点
1)提取公共部分代码,便于维护
提取公共代码可以使核心代码变少,放在一起方便维护,想修改某个方法只需要修改一处就可以了
2)行为由父类控制,子类实现
自己的理解父类定义你有哪些行为,子类具体实现,其具体实现不关父类的事。就像小时候老妈喊你写完家庭作业,但是你具体怎么做并不会管,你是先写语文呢,还是先写数学呢
3)封装不变部分,扩展可变部分
(四)使用场景
1)多个子类有共有方法,并且逻辑基本相同时
2)重构时,把相同的代码抽取到父类中,通过钩子函数约(钩子函数自我理解就是一个返回值为boolean的方法,通过返回值来控制其他行为,在抽象类中可以有默认实现)约束其行为
感觉2)说的就是1)啊
(五)简单例子:
抽象类:HummerModel.java
public abstract class HummerModel {
public abstract void start();
public abstract void stop();
public abstract void alarm();
public abstract void engineBoom();
public void run() {
this.start();
this.engineBoom();
this.alarm();
this.stop();
}
}
子类一:HummerH1Model.java
public class HummerH1Model extends HummerModel {
@Override
public void start() {
System.out.println("悍马h1发动");
}
@Override
public void stop() {
System.out.println("悍马h1停车");
}
@Override
public void alarm() {
System.out.println("悍马h1鸣笛");
}
@Override
public void engineBoom() {
System.out.println("悍马h1引擎声音是这样的");
}
}
子类二:HummerH2Model.java
public class HummerH2Model extends HummerModel {
@Override
public void start() {
System.out.println("悍马h2发动");
}
@Override
public void stop() {
System.out.println("悍马h2停车");
}
@Override
public void alarm() {
System.out.println("悍马h2鸣笛");
}
@Override
public void engineBoom() {
System.out.println("悍马h2引擎声音是这样的");
}
}
有了这个例子在解释一下一下什么是模板方法模式:先介绍两个概念,上述抽象类中start(),stop(), alarm(),engineBoom()这几个为基本方法,需要在子类中重写这些方法,run()方法为模板方法,一个具体的方法,在模板方法里面对基本方法进行顺序调用。模板方法模式就是在模板方法中按照一定的规则和顺序调用基本的方法。
(六)模板方法在框架中的应用
在框架中应用十分广泛,这里讲解一下自己稍微比较熟悉的AQS框架中模板方法模式
一个使用AQS完成的自定义独占锁:Mutex.java
public class Mutex implements Lock {
//继承同步器的子类作为静态内部类
private static class Sync extends AbstractQueuedLongSynchronizer {
//判断锁是否已经被其他线程所占用了
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
//当状态为0时获得锁(0:此时没有线程获得锁)
@Override
protected boolean tryAcquire(long arg) {
//cas设置同步状态
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
//释放锁
@Override
protected boolean tryRelease(long arg) {
if (getState() == 0) {
throw new IllegalMonitorStateException(); //如果根本没有获得锁,但是你去释放将抛出异常
}
setExclusiveOwnerThread(null);
setState(0); //设置同步状态
return true;
}
Condition newCondition() {
return new ConditionObject();
}
}
private final Sync sync = new Sync();
//Lock接口中的方法
//使用静态内部类的方法来实现自己想实现的语义
@Override
public void lock() {
sync.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() {
sync.release(1);
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
//自定义方法
public boolean isLocked() {
return sync.isHeldExclusively();
}
}
其中tryRelease(long arg),tryAcquire(long arg),isHeldExclusively()都是需要在子类中进行重写的方法
框架中的方法
protected boolean tryAcquire(long arg) {
throw new UnsupportedOperationException();
}
protected boolean tryRelease(long arg) {
throw new UnsupportedOperationException();
}
protected boolean isHeldExclusively() {
throw new UnsupportedOperationException();
}
子类中Sync都对这些方法进行了重写
而acquire(long arg),release(long arg)为模板方法,在模板方法中调用重写方法
框架中的这些方法:
public final void acquire(long arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
public final boolean release(long arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
可以看到在acquire(long arg)模板方法中调用了tryAcquire(long arg)这个重写方法,而release(long arg)模板方法中调用了tryRelease(long arg)这个重写方法
(七)自我理解
最后谈谈自己的理解,模板方法模式在开源框架中使用到比较多吧,感觉自己写项目的时候就很少使用这种设计模式,用的多是接口,面向接口编程。刚开始以为抽象类,子类继承抽象类重写这些方法就算是使用了模板方法模式,其实并不是,两者之间还是有区别的,模板方法模式的重点是模板方法。
网友评论