(15)模版方法设计模式

一、概念

        模板设计模式—基于抽象类的,核心是封装算法

        模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供具体实现,使用模板方法模式有Spring、Servlet、AQS等

        在一个方法中定义一个算法的骨架,并将一些具体步骤延迟到子类中实现。模板模式使得子类在不改变算法结构的基础上,重新具体定义算法中的某些步骤,提高代码复用性。

优点

        使用模版方法模式,在定义算法骨架的同时,可以很灵活的实现具体的算法,满足用户灵活多变的需求

缺点

        如果算法骨架有修改的话,则需要修改抽象类

步骤

1、先将主流程框架逻辑(清点商品/计算价目/结算/送货上门)设计完成

2、再实现各模块小步骤。

3、不能确实的步骤,作为虚拟方法,甩锅给子类实现。

4、子类只需要聚焦自己的小步骤逻辑。

讲模板设计模式之前,我们用代码来实现咖啡和茶制作的类:

普通类写法

public class MakeDrink {
    public static void main(String[] agrs) {
        Coffee coffee = new Coffee();
        coffee.makeCoffee();
        System.out.println("~~~~~~");
        Tea tea = new Tea();
        tea.makeTea();
    }
}
//制作咖啡
class Coffee {
    //make coffee
    void makeCoffee() {
        boilWater();
        brewCoffeeGrings();
        pourInCup();
        addSugarAndMilk();
    }
    // setp1:
    public void boilWater() {
        System.out.println("将水煮沸");
    }
     // setp2:
    public void brewCoffeeGrings() {
        System.out.println("冲泡咖啡");
    }
     // setp3:
    public void pourInCup() {
        System.out.println("把咖啡倒进杯子中");
    }
     // setp4:
    public void addSugarAndMilk() {
        System.out.println("加糖和牛奶");
    }
}
// 制作茶
class Tea {
    //make tea
    void makeTea() {
        boilWater();
        steepTeaBag();
        pourInCup();
        addLemon();
    }
     // setp1:
    public void boilWater() {
        System.out.println("将水煮沸");
    }
     // setp2:
    public void steepTeaBag() {
        System.out.println("浸泡茶叶");
    }
     // setp3:
    public void pourInCup() {
        System.out.println("把茶倒进杯子中");
    }
     // setp4:
    public void addLemon() {
        System.out.println("加柠檬");
    }
}

我们在coffee和Tea两个类中发现了重复代码,因此我们需要重新理一下我们的设计。

既然茶和咖啡是如此的相似,因此我们应该将共同的部分抽取出来,放进一个基类中。从冲泡法入手。观察咖啡和茶的冲泡法我们会发现,两种冲泡法都采用了相同的算法:

  • 将水煮沸
  • 用热水泡饮料
  • 把饮料倒进杯子
  • 在饮料内加入适当的调料

实际上,浸泡(steep)和冲泡(brew)差异并不大。因此我们给它一个新的方法名称brew(),这样我们无论冲泡的是何种饮 料都可以使用这个方法。

同样的,加糖、牛奶还是柠檬也很相似,都是在饮料中加入其它调料,因此我们也给它一个通用名称addCondiments()。

另外,不管泡咖啡还是冲茶,其实都是做饮品,我们改算法的名字为makingDrinks

模版方法设计模式

/**
 * 模板方法设计模式
 */
public class TemplateMethodPatternTest1 {
    /**
     * 模版方法抽象类
     */
    abstract class DrinkProduction {
        /**
         *  生产饮料的步骤
         *  final禁止子类重写
         */
        public final void makingDrinks() {
            boilWater();
            brew();
            pourInCup();
            addCondiments();
        }

        /**
         * 步骤一:烧水
         */
        public void boilWater() {
            System.out.println("将水煮沸");
        }

        /**
         * 步骤二:加主料
         * 强制子类实现
         */
        public abstract void brew();

        /**
         * 步骤三:倒入茶杯
         */
        public void pourInCup() {
            System.out.println("倒入杯子里");
        }

        /**
         * 步骤四:加佐料
         * 强制子类实现
         */
        public abstract void addCondiments();
    }
    // 做咖啡
    class Coffee extends DrinkProduction {
        @Override
        public void addCondiments() {
            System.out.println("添加牛奶和糖");
        }

        @Override
        public void brew() {
            System.out.println("加入coffee煮");
        }
    }
    // 做茶
    class Tea extends DrinkProduction {
        @Override
        public void addCondiments() {
            System.out.println("加入柠檬");
        }

        @Override
        public void brew() {
            System.out.println("加入茶叶煮");
        }
    }
    public void test(){
        Coffee coffee = new Coffee();
        coffee.makingDrinks();
        System.out.println("~~~~~~");
        Tea tea = new Tea();
        tea.makingDrinks();
    }
    public static void main(String[] args) {
        TemplateMethodPatternTest1 tem = new TemplateMethodPatternTest1();
        tem.test();
    }
}

uml图

在模板设计模式下还有一种钩子用法

        钩子方法是一类"默认不做事的方法" ,子类可以视情况决定要不要覆盖它们。

        比如说,泡茶的时候,最后一步不用加柠檬

/**
 * 有钩子的模版方法设计模式
 */
public class TemplateMethodPatternTest2 {
    /**
     * 模版方法抽象类
     */
    abstract class DrinkProduction {
        /**
         *  生产饮料的步骤
         *  final禁止子类重写
         */
        public final void makingDrinks() {
            boilWater();
            brew();
            pourInCup();
            //钩子决定是否调用
            if(isAddCondiments()) {
                addCondiments();
            }
        }

        /**
         * 步骤一:烧水
         */
        public void boilWater() {
            System.out.println("将水煮沸");
        }

        /**
         * 步骤二:加主料
         */
        public abstract void brew();

        /**
         * 步骤三:倒入茶杯
         */
        public void pourInCup() {
            System.out.println("倒入杯子里");
        }

        /**
         * 步骤四:加佐料
         */
        public abstract void addCondiments();

        /**
         * 钩子写法
         * 如果不需要就对这个方法重写
         * @return
         */
        public boolean isAddCondiments(){
            return true;
        }
    }

    class Coffee extends DrinkProduction {
        @Override
        public void brew() {
            System.out.println("加入coffee继续煮");
        }

        @Override
        public void addCondiments() {
            System.out.println("添加牛奶和糖");
        }
    }

    class Tea extends DrinkProduction {
        @Override
        public void brew() {
            System.out.println("加入茶叶煮");
        }

        // 不需要实现,空方发即可
        @Override
        public void addCondiments() {
        }

        @Override
        public boolean isAddCondiments(){
            return false;
        }
    }
    public void test(){
        Coffee coffee = new Coffee();
        coffee.makingDrinks();
        System.out.println("~~~~~~");
        Tea tea = new Tea();
        tea.makingDrinks();
    }
    public static void main(String[] args) {
        TemplateMethodPatternTest2 tem = new TemplateMethodPatternTest2();
        tem.test();
    }
}

二、分析jdbcTemplate的模板方法设计模式用法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值