模板方法模式

如果你不相信努力和时光,那么成果就会是第一个选择辜负你的。不要去否定你自己的过去,也不要用你的过去牵扯你现在的努力和对未来的展望。不是因为拥有希望你才去努力,而是去努力了,你才有可能看到希望的光芒。模板方法模式,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

概述

《设计模式》一书中对于 “模板方法模式” 的意图描述如下:

定义一个操作中的算法骨架,而将一些步骤延迟到子类中

一般在以下几种情况下使用模板方法模式:

  • 一次性实现一个算法的不可变部分,并将可变的行为留给子类来实现
  • 各个子类中的公共行为应当被提取出来并集中到一个公共父类中以避免重复代码(提炼父类
  • 控制子类的扩展。模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展

具体示例

Java 中比较经典的是 AQSAbstractQueuedSynchronizer),这是 Java 中所有同步工具类都需要使用到的同步框架,具体同步工具,如 LockReadWriteLockCountDownLatch 都是通过继承这个类并改变一些默认的实现来达到对应的目的

比如,如果希望自定义一个互斥锁,那么只需要继承 AQS 并重写 tryAcquiretryRelease 方法即可:

public class SelfLock {
    // 实际执行同步操作的同步类
    private final class Sync extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquired(int arg) { // 这个方法用于检测是否成功获取锁
            Thread t = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, arg)) {
                    setExclusiveOwnerThread(t);
                    return true;
                }
            } else if (t == getExclusiveOwnerThread()) {
                setState(c + arg);
                return true;
            }
            return false;
        }
        
        @Override
        protected boolean tryRelease(int arg) { // 这个方法的目的是检查已经获取锁的线程是否完全释放了锁
            int c = getState() - arg;
            boolean res = false;
            if (c == 0) {
                setExclusiveOwnerThread(null);
                res = true;
            }
            setState(c);
            return res;
        }
    }
    
    private final Sync sync = new Sync();
    
    public void lock() {
        sync.acquire(1); // 实际通过 AQS 来获取锁,同时由 AQS 维护同步队列状态
    }
    
    public void unlock() {
        sync.release(1); // 实际调用 AQS 来释放锁,并维护同步队列状态
    }
}

而在 AQS 内部,acquirerelease 方法如下:

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {
    // 省略部分其它方法
    
    public final void acquire(int arg) {
        /*
        	只要 tryAcquire 方法返回 false,就将当前线程封装成一个节点放入 AQS 的阻塞队列中进行后续的处理,
        	否则将视为成功获取到锁
        */
        if (!tryAcquire(arg) && 
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    
    public final boolean release(int arg) {
        /*
        	只要 tryRelease 方法返回 false,就视为释放锁失败,当返回 true 时视为释放所成功,
        	同时唤醒后继节点
        */
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
}

由于篇幅原因,具体 AQS 的处理细节在此省略,感兴趣的话可以看看 AQS 解析,本文仅简要介绍其中有关模板方法模式的使用

总结

通过模板方法模式,可以封装相关的固定算法,而将一些细节交给子类来完成,这一设计模式在实际开发过程中也特别常见,特别是在实现框架类的需求时


参考:

[1] 《设计模式—可复用面向对象基础》

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/197500.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!