【设计模式精解】从根上理解模板方法设计模式及其应用

发布于:2025-08-08 ⋅ 阅读:(18) ⋅ 点赞:(0)

目录

模板方法模式有哪些应用?

概念

模板方法设计模式之前是怎么写代码的?

代码示例

代码结构图

模板方法设计模式样例

UML类图

代码示例

AQS是怎么应用模板方法设计模式的?

acquire()具体是什么流程呢?

模板方式设计模式的优缺点


模板方法模式有哪些应用?

在很多时候,我们的代码中可能会有一些公共的部分并且还有一些定制的部分,那么公共这部分就可以定义在一个父类中,然后将定制的部分实现在子类中。这样子类可以根据需要扩展或重写父类的方法,而不需要改变算法的结构。

概念

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤,这种类型的设计模式属于行为型模式。

模板方法设计模式之前是怎么写代码的?

代码示例

以一个试卷为例,每个学生都需要把试卷上的题目抄一遍并且选择答案,代码如下:

public class PaperA {

    // 试题一
    public void question1() {
        System.out.println("第一题的题目是:1+1=?");
        System.out.println("第一题的答案选择" + "A");
    }

    // 试题二
    public void question2() {
        System.out.println("第二题的题目是1+2=?");
        System.out.println("第二题的答案选择" + "B");
    }

    // 试题三
    public void question3() {
        System.out.println("第三题的题目是1+3=?");
        System.out.println("第三题的答案选择" + "C");
    }
}
public class PaperB {
    // 试题一
    public void question1() {
        System.out.println("第一题的题目是:1+1=?");
        System.out.println("第一题的答案选择" + "B");
    }

    // 试题二
    public void question2() {
        System.out.println("第二题的题目是1+2=?");
        System.out.println("第二题的答案选择" + "D");
    }

    // 试题三
    public void question3() {
        System.out.println("第三题的题目是1+3=?");
        System.out.println("第三题的答案选择" + "A");
    }
}
public class Client {
    public static void main(String[] args) {
        System.out.println("学生甲的试卷-------------");
        PaperA paperA = new PaperA();
        paperA.question1();
        paperA.question2();
        paperA.question3();

        System.out.println("学生乙的试卷-------------");
        PaperB paperB = new PaperB();
        paperB.question1();
        paperB.question2();
        paperB.question3();
    }
}

可以感觉到学生甲和学生乙两个抄试卷类非常类似,除了答案不同,没什么不一样的,假设老师突然要改代码,如果某人抄错了,那就糟糕了。

所以我们的解决办法是老师出一根试卷,打印多份,让学生写答案就行。也就是抽象出一个父类,让两个子类继承,公共的试题代码写到父类当中就可以,下面我来写写看。

// 抽象父类
public abstract class Paper {
    public void question1() {
        System.out.println("第一题的题目是1+1=?");
        System.out.println("第一题的答案选择" + answer1());
    }

    // 子类需要重写的方法
    public abstract String answer1();

    public void question2() {
        System.out.println("第二题的题目是1+2=?");
        System.out.println("第二题的答案选择" + answer2());
    }

    // 子类需要重写的方法
    public abstract String answer2();

    public void question3() {
        System.out.println("第三题的题目是1+3=?");
        System.out.println("第三题的答案选择" + answer3());
    }

    // 子类需要重写的方法
    public abstract String answer3();
}
public class PaperA extends Paper {
    @Override
    public String answer1() {
        return "A";
    }

    @Override
    public String answer2() {
        return "B";
    }

    @Override
    public String answer3() {
        return "C";
    }
}
public class PaperB extends Paper {
    @Override
    public String answer1() {
        return "B";
    }

    @Override
    public String answer2() {
        return "D";
    }

    @Override
    public String answer3() {
        return "A";
    }
}

客户端程序

public class Client {
    public static void main(String[] args) {
        System.out.println("学生甲的试卷-------------");
        PaperA paperA = new PaperA();
        paperA.question1();
        paperA.question2();
        paperA.question3();
        System.out.println("学生乙的试卷-------------");
        PaperB paperB = new PaperB();
        paperB.question1();
        paperB.question2();
        paperB.question3();
    }
}

代码结构图

模板方法设计模式样例

UML类图

代码示例

// 抽象类,定义模板方法
public abstract class AbstractClass {

    // 模板方法,定义了算法的主要步骤
    public final void templateMethod() {
        primitiveOperation1(); // 调用第一个具体步骤
        primitiveOperation2(); // 调用第二个具体步骤
    }

    // 抽象方法,由子类实现
    protected abstract void primitiveOperation1();

    // 抽象方法,由子类实现
    protected abstract void primitiveOperation2();
}

// 子类A,实现抽象方法
public class ClassA extends AbstractClass {

    @Override
    protected void primitiveOperation1() {
        // 实现具体步骤A1
        System.out.println("ClassA primitiveOperation1");
    }

    @Override
    protected void primitiveOperation2() {
        // 实现具体步骤A2
        System.out.println("ClassA primitiveOperation2");
    }
}

// 子类B,实现抽象方法
public class ClassB extends AbstractClass {

    @Override
    protected void primitiveOperation1() {
        // 实现具体步骤B1
        System.out.println("ClassB primitiveOperation1");
    }

    @Override
    protected void primitiveOperation2() {
        // 实现具体步骤B2
        System.out.println("ClassB primitiveOperation2");
    }
}

客户端程序

// 客户端代码
public class Client {
    public static void main(String[] args) {
        AbstractClass classA = new ClassA();
        classA.templateMethod(); // 输出:ClassA primitiveOperation1, ClassA primitiveOperation2

        AbstractClass classB = new ClassB();
        classB.templateMethod(); // 输出:ClassB primitiveOperation1, ClassB primitiveOperation2
    }
}

AQS是怎么应用模板方法设计模式的?

AQS是一个抽象类,它内部定义了一些公共的方法,这些公共的方法有获取锁acquire(),还有释放锁release()、等方法。也就是把这个架子搭好了,你自己用的时候需要让子类继承这个抽象类然后重写tryAcquire(),tryRelease()方法,这就是一个典型的模板方法的应用。

AQS类中 , 公共方法 描述
public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
独占获取的同步状态
它调用了子类重写的tryAcquire方法,如果获取成功,直接返回,否则接着走其他方法进度等待队列
public final boolean release(int arg) {
        if (tryRelease(arg)) {
                Node h = head;
                if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
                return true;
        }
        return false;
}
独占式释放同步状态
释放成功后,把同步队列中第一个节点内的线程唤醒

acquire()具体是什么流程呢?

就是if里的方法的执行顺序:
tryAcquire()--->addWaiter(Node.EXCLUSIVE)--------------------->acquireQueued(##,arg)-------------------------->selfInterrupt()

获取锁--------->获取失败后,请求锁的线程包装成Node,放入队列--->刚包装成Node的线程,让它尝试获取锁或挂起---->中断当前线程

整合一下上面的图:

Semaphore 的重写方法

public boolean tryAcquire(int permits) {
    if (permits < 0) throw new IllegalArgumentException();
    return sync.nonfairTryAcquireShared(permits) >= 0;
}

模板方式设计模式的优缺点

优点:尽可能的将重复的代码提升带父类中去,子类只描述特化的那一部分代码。大大降低代码的重复度。
缺点:父类与子类之间的调用关系复杂,增加了代码阅读难度;通过继承实现,如果父类添加新的抽象方法,所有子类都需要修改。

如果我的内容对你有帮助,请辛苦动动您的手指为我点赞,评论,收藏。感谢大家。


网站公告

今日签到

点亮在社区的每一天
去签到