您的位置: 首页 - 站长

wordpress 网站 上传网站 备案

当前位置: 首页 > news >正文

wordpress 网站 上传,网站 备案,wordpress页面发布不,许昌市做网站设计模式浅析(九) 模板方法模式 日常叨逼叨 java设计模式浅析#xff0c;如果觉得对你有帮助#xff0c;记得一键三连#xff0c;谢谢各位观众老爷#x1f601;#x1f601; 模板方法模式 概念 模板方法模式#xff08;Template Method Pattern#xff09;在Java中是…设计模式浅析(九) ·模板方法模式 日常叨逼叨 java设计模式浅析如果觉得对你有帮助记得一键三连谢谢各位观众老爷 模板方法模式 概念 模板方法模式Template Method Pattern在Java中是一种非常实用的设计模式它允许我们在一个方法中定义一个算法的骨架同时允许子类在不改变算法结构的情况下重新定义某些步骤的具体内容。这种模式非常适合于那些算法的整体步骤固定但某些步骤的具体实现可能因需求不同而有所变化的场景。 组成 抽象类Abstract Class 定义了一个或多个抽象方法这些抽象方法由具体子类来实现。包含一个模板方法这个方法定义了算法的骨架并调用了在抽象类中定义的抽象方法。模板方法通常被声明为final以防止子类覆盖它。模板方法通常还包含一些普通方法这些方法可以被具体子类直接使用或覆盖。 具体子类Concrete Subclasses 实现了抽象类中定义的抽象方法提供了这些抽象方法的具体实现。通过继承抽象类子类可以重写普通方法以提供不同的实现。子类可以通过调用父类的模板方法来执行算法。 客户端 客户端代码创建具体类的实例并调用模板方法来执行算法。
案例 继续以一家饮品店为例子 A饮品店有咖啡coffee和茶tea两种饮品对于其制作方法如下 咖啡冲泡法 (1)把水煮沸 (2)用沸水冲泡咖啡 (3)把咖啡倒进杯子 (4)加糖和牛奶 茶水冲泡法 (1)把水煮沸 (2)用沸水浸泡茶叶 (3)把茶倒进杯子 (4)加柠檬 让我们扮演冲泡师傅快速的创建茶水和咖啡 //coffee public class Coffee {void prepareRecipe() {boilWater();brewCoffeeGrinds();pourInCup();addSugarAndMilk();}public void boilWater() {System.out.println(step 1 Boiling water);}public void brewCoffeeGrinds() {System.out.println(step 2 Dripping Coffee through filter);}public void pourInCup() {System.out.println(step 3 Pouring into cup);}public void addSugarAndMilk() {System.out.println(step 4 Adding Sugar and Milk);} }//Tea public class Tea {void prepareRecipe() {boilwater();steepTeaBag();pourInCup();addLemon();}public void boilwater() {System.out.println(step 1 Boiling water);}public void steepTeaBag() {System.out.println(step 2 Steeping the tea);}public void addLemon() {System.out.println(step 3 Adding Lemon);}public void pourInCup() {System.out.println(step 4 Pouring into cup);} }仔细观察上述的代码会发现coffee和tea 除了第2步骤和第4步骤不一样外其他的步骤几乎一致代码存在者较高的冗余。是不是可以将一些代码抽取出来 那么第一次抽取之后类图可能会变成这个样子 但是仔细想一想上面的制作方法 让我们来思考这一点:浸泡(steep)和冲泡(brew)差异其实不大。所以我们给它一个新的方法名称比方说brew()然后不管是泡茶或冲泡咖啡我们都用这个名称。 类似地加糖和牛奶也和加柠檬很相似:都是在饮料中加入调料由此我们再做一次公共的提取。 首先我们定义一个抽象类DrinksMake在其中定义一个final的方法规定具体的步骤 abstract class DrinksMake {//模板方法public final void makeDrinks() {//step 1 烧水boiledWater();//step 2 冲泡brew();//step3 倒出到杯子中pourInCup();//step4 添加配料addTheIngredients();}protected abstract void addTheIngredients();protected abstract void brew();protected void boiledWater() {System.out.println(step1:boiled water!);}protected void pourInCup() {System.out.println(step3: pourInCup !);}}然后我们定义制作咖啡的具体实现以及茶水的具体实现 public class CoffeeMake extends DrinksMake {Overrideprotected void addTheIngredients() {System.out.println(step 4 : add Sugar and Milk into Coffee);}Overrideprotected void brew() {System.out.println(step 2 : brew Coffee);} }public class TeaMake extends DrinksMake {Overrideprotected void addTheIngredients() {System.out.println(step 4 : add Lemon into tea);}Overrideprotected void brew() {System.out.println(step 2 : brew tea);} }那么对于客户端来说我们分别制作一杯咖啡和一杯茶 public class Client {public static void main(String[] args) {TeaMake teaMake new TeaMake();CoffeeMake coffeeMake new CoffeeMake();teaMake.makeDrinks();coffeeMake.makeDrinks();} }运行结果 step1:boiled water! step 2 : brew tea step3: pourInCup ! step 4 : add Lemon into tea step1:boiled water! step 2 : brew Coffee step3: pourInCup ! step 4 : add Sugar and Milk into Coffee Process finished with exit code 0 至此我们实现了设计模式中的模板方法模式 模板方法模式中的钩子hook 我们在上述的抽象父类中再加入一个方法 void hook(){} //但是这个方法暂时什么都不做我们也可以有默认不做事的方法我们称这神方法为hook(钩子)。子类可以视情况决定要不要覆盖它们。接下来就会知道钩子的实际用途。 试想一下如果在step4添加小料的时候是不是应该询问一下顾客的意见不能问不问就为顾客添加一些小料这个是不太合理的那么我们的代码可以这么修改 abstract class DrinksMake {//模板方法public final void makeDrinks() {//step 1 烧水boiledWater();//step 2 冲泡brew();//step3 倒出到杯子中pourInCup();//step4 添加配料if (ifNeedIngredients()) {addTheIngredients();}}protected abstract void addTheIngredients();protected abstract void brew();protected void boiledWater() {System.out.println(step1:boiled water!);}protected void pourInCup() {System.out.println(step3: pourInCup !);}/**** 钩子方法子类可以选择重写或者不重写*/boolean ifNeedIngredients() {return true;}}创建一个类似于钩子的方法默认返回是添加小料可以在子类中进行重写进行相关的操作我们可以在子类中进行询问顾客是否需要小料 public class CoffeeMakeWithHook extends DrinksMake {Overrideprotected void addTheIngredients() {System.out.println(step 4 : add Sugar and Milk into Coffee);}Overrideprotected void brew() {System.out.println(step 2 : brew Coffee);}Overrideboolean ifNeedIngredients() {String answer getUserInput();if (answer.toLowerCase().startsWith(y)) {return true;} elsereturn false;}// 让用户输入他们对调料的决定。根据用户的输入返回tue或falseprivate String getUserInput() {String answer null;System.out.print(would you like milk and sugar with your coffee (y/n) ?);BufferedReader in new BufferedReader(new InputStreamReader(System.in));try {answer in.readLine();} catch (IOException e) {System.err.println(IO error trying to read your answer);}if (answer null) {return no;}return answer;} } 再次创建客户端代码进行coffeewithhook的调用 public class Client {public static void main(String[] args) {CoffeeMakeWithHook coffeeMake new CoffeeMakeWithHook();coffeeMake.makeDrinks();} }运行结果如下: 不需要小料 step1:boiled water! step 2 : brew Coffee step3: pourInCup ! would you like milk and sugar with your coffee (y/n) ?n Process finished with exit code 0 需要小料 step1:boiled water! step 2 : brew Coffee step3: pourInCup ! would you like milk and sugar with your coffee (y/n) ?y step 4 : add Sugar and Milk into Coffee Process finished with exit code 0 优缺点 优点 代码复用模板方法模式允许你定义一个算法的骨架而将一些步骤延迟到子类中。这允许子类在不改变算法结构的情况下重定义某些步骤的具体内容从而实现了代码的复用。扩展性由于模板方法模式将算法中的固定部分与可变部分分离这使得子类可以通过扩展来增加新的行为从而提高了代码的扩展性。封装性通过将不变的部分封装在父类中模板方法模式隐藏了实现细节只暴露必要的接口给子类。这有助于减少子类的耦合度。行为控制模板方法模式允许通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行从而提供了一种反向控制结构。 缺点 代码可读性由于模板方法模式中的钩子方法和抽象方法的调用顺序可能比较复杂这可能会增加代码的阅读难度尤其是对于新手来说。继承的缺点模板方法模式依赖于继承来实现代码复用而继承本身有一些固有的缺点如破坏封装性、子类与父类之间的强耦合等。扩展限制如果父类中的模板方法被声明为final那么子类将无法覆盖该方法这可能会限制子类的扩展性。 总的来说Java模板方法模式在需要定义一系列复杂算法时非常有用它能够有效地实现代码复用和扩展。然而它也有一些缺点需要注意如代码可读性和继承的局限性等。因此在使用模板方法模式时需要根据具体情况权衡其优缺点。 代码相关代码可以参考 代码仓库 ps本文原创转载请注明出处