四。 模板方法模式
Definition: Define the skeleton of an algorithm in an operation, deferring some steps to subclasses.
Templet Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
它包含一個抽象模板和一些具體的模板。
抽象模板中包含兩類方法:
- 基本方法
- 也叫基本操作,是有抽象模板給出抽象接口,子類給出實現的方法,並且這些方法會在模板方法中被調用;
- 基本方法盡量設計為protected類型,符合迪米特法則
- 模板方法
- 可以有一個或幾個,一般是一個具體方法,實現對基本方法的調度,完成固定的邏輯。
- 為了防止惡意的操作,,一般模板方法都會加上final關鍵字,不允許被覆寫。
Demo Coding:

package com.model; 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(); } } package com.model; public class HummerH1Model extends HummerModel { @Override public void start() { // TODO Auto-generated method stub System.out.println("H1型號是這樣啟動的....."); } @Override public void stop() { // TODO Auto-generated method stub System.out.println("H1型號是這樣停止的....."); } @Override public void alarm() { // TODO Auto-generated method stub System.out.println("H1型號是這樣鳴笛的......"); } @Override public void engineBoom() { // TODO Auto-generated method stub System.out.println("H1型號是這樣發動引擎的......"); } } package com.model; public class HummerH2Model extends HummerModel { @Override public void start() { // TODO Auto-generated method stub System.out.println("H2型號是這樣啟動的......"); } @Override public void stop() { // TODO Auto-generated method stub System.out.println("H2型號是這樣停止的......"); } @Override public void alarm() { // TODO Auto-generated method stub System.out.println("H2型號是這樣鳴笛的......"); } @Override public void engineBoom() { // TODO Auto-generated method stub System.out.println("H2型號是這樣發動引擎的......"); } } package com.model; public class Client { public static void main(String[] args) { // TODO Auto-generated method stub //某公司要H1模型的悍馬汽車 HummerModel hm = new HummerH1Model(); //H1模型演示如下 hm.run(); } }
五。 建造者模式(Builder Pattern)
Definition: Separate the construction of a complex object from its representation so that the same
construction process can create different representations.
在一般的建造者模式中,有如下4個角色:
- 產品類(實際就是上面的第四種模板方法模式的實現)
- 通常是實現了模板方法模式,也就是有模板方法和基本方法;
- 抽象建造者Builder
- 規范產品的組建,一般由子類實現。
- 具體構建着ConcreteBuilder
- 實現抽象建造者的所有方法,並且返回一個組建好的對象。
- 導演類
- 負責根據客戶的需要安排已有模塊的順序,然后告訴Builder開始建造,然后獲得ConcreteBuilder返回的對象,最后呈現給客戶
所以說,不論是經由模板模式構建的產品類還是抽象或具體的建造者,對於客戶都是屏蔽的,客戶只需要將他的具體需求告訴導演類,最終由導演類統籌安排,將結果返回給客戶。
建造者模式的使用場景有:
- 如果需求是:相同的方法,不同的執行順序,產生不同的事件結果時,可以考慮使用。
- 一個對象由多個零件或部件構成,,但是運行產生的結果又不相同;
- 所以,,建造者模式關注的是零件類型和裝配順序不同!!!這是他與工廠方法最大的不同!!
- 工廠模式的重點則是創建,創建零件的它的主要職責,組裝順序是它不care的!!
Demo Coding:

/*-------------------------模板方法模式的實現-----------------------------*/ package com.builderPattern; import java.util.ArrayList; public abstract class CarModel { //這個參數是各個基本方法執行的順序 private ArrayList<String> sequence = new ArrayList<String>(); protected abstract void start(); protected abstract void stop(); protected abstract void alarm(); protected abstract void engineBoom(); final public void run() { //循環一遍sequence,誰在前就限制性誰 for(int i=0; i<this.sequence.size(); i++) { String actionName = this.sequence.get(i); if(actionName.equalsIgnoreCase("start")) this.start(); else if(actionName.equalsIgnoreCase("stop")) this.stop(); else if(actionName.equalsIgnoreCase("alarm")) this.alarm(); else if(actionName.equalsIgnoreCase("engine boom")) this.engineBoom(); } } final public void setSequence(ArrayList<String> sequence) { this.sequence = sequence; } } package com.builderPattern; public class BenzModel extends CarModel { @Override protected void start() { // TODO Auto-generated method stub System.out.println("奔馳是這樣run...."); } @Override protected void stop() { // TODO Auto-generated method stub System.out.println("奔馳是這樣stop...."); } @Override protected void alarm() { // TODO Auto-generated method stub System.out.println("奔馳是這樣alarm...."); } @Override protected void engineBoom() { // TODO Auto-generated method stub System.out.println("奔馳是這樣engine boom....."); } } package com.builderPattern; public class BMWModel extends CarModel { @Override protected void start() { // TODO Auto-generated method stub System.out.println("寶馬是這樣start...."); } @Override protected void stop() { // TODO Auto-generated method stub System.out.println("寶馬是這樣stop...."); } @Override protected void alarm() { // TODO Auto-generated method stub System.out.println("寶馬是這樣alarm...."); } @Override protected void engineBoom() { // TODO Auto-generated method stub System.out.println("寶馬是這樣engine boom...."); } } /*-------------------------抽象建造者-----------------------------*/ package com.builderPattern; import java.util.ArrayList; public abstract class CarBuilder { //建造一個模型,你要給我一個順序,就是組裝順序 public abstract void setSequence(ArrayList<String> sequence); //設置完順序后,既可以直接拿到這個車輛模型 public abstract CarModel getCarModel(); } /*--------------具體建造者的實現,返回一個具體的model------------------------*/ package com.builderPattern; import java.util.ArrayList; public class BenzBuilder extends CarBuilder { private BenzModel benz = new BenzModel(); @Override public void setSequence(ArrayList<String> sequence) { // TODO Auto-generated method stub this.benz.setSequence(sequence); } @Override public CarModel getCarModel() { // TODO Auto-generated method stub return this.benz; } } package com.builderPattern; import java.util.ArrayList; public class BMWBuilder extends CarBuilder { private BMWModel bmw = new BMWModel(); @Override public void setSequence(ArrayList<String> sequence) { // TODO Auto-generated method stub this.bmw.setSequence(sequence); } @Override public CarModel getCarModel() { // TODO Auto-generated method stub return this.bmw; } } /*-------------------------導演類的實現,實現客戶的需求-------------------------*/ package com.builderPattern; import java.util.ArrayList; public class Director { private ArrayList<String> sequence = new ArrayList<String>(); private BenzBuilder benzBuilder = new BenzBuilder(); private BMWBuilder bmwBuilder = new BMWBuilder(); /** * 獲得A類型的奔馳汽車 * @return */ public BenzModel getABenzModel() { this.sequence.clear(); this.sequence.add("start"); this.sequence.add("stop"); this.benzBuilder.setSequence(sequence); return (BenzModel) this.benzBuilder.getCarModel(); } /** * 獲得B類型的奔馳汽車 * @return */ public BenzModel getBBenzModel() { this.sequence.clear(); this.sequence.add("engine boom"); this.sequence.add("start"); this.sequence.add("stop"); this.benzBuilder.setSequence(sequence); return (BenzModel) this.benzBuilder.getCarModel(); } /** * 獲得A類型的寶馬車型 * @return */ public BMWModel getABMWModel() { this.sequence.clear(); this.sequence.add("alarm"); this.sequence.add("start"); this.sequence.add("stop"); this.bmwBuilder.setSequence(sequence); return (BMWModel) this.bmwBuilder.getCarModel(); } /** * 獲得B類型的寶馬車型 * @return */ public BMWModel getBBMWModel() { this.sequence.clear(); this.sequence.add("start"); this.bmwBuilder.setSequence(sequence); return (BMWModel) this.bmwBuilder.getCarModel(); } } package com.builderPattern; public class Client { public static void main(String[] args) { // TODO Auto-generated method stub Director director = new Director(); //制造100台A類型的奔馳 for(int i=0; i<1000; i++) director.getABenzModel().run(); for(int i=0; i<2000; i++) director.getBBMWModel().run(); } }
六。代理模式(Proxy Pattern)
Definition: Provide a surrogate or placeholder for another object to control access to it.
在代理模式中,有三個角色的定義:
- Subject抽象主題角色
- 抽象主題可以是抽象類也可以是接口,是一個最普通的業務類型定義;
- RealSubject具體主題角色
- 也叫作被委托角色。是具體業務邏輯的具體執行者;
- Proxy代理主題角色
- 也叫委托類、代理類,它負責對真實角色的應用,把所有抽象主題類定義的方法委托給真實主題角色實現,並且在真實主題角色處理完畢后做預處理和善后工作;
- RealSubject 和 Proxy都繼承自Subject
Demo Coding:

package com.proxyPattern; public interface IGamePlayer { //玩家登陸 public void login(String name, String password); //打boss public void killBoss(); //升級 public void upgrade(); } package com.proxyPattern; public class GamePlayer implements IGamePlayer { private String name = ""; public GamePlayer(String name) { this.name = name; } @Override public void login(String name, String password) { // TODO Auto-generated method stub System.out.println("Congradulation! " + this.name + " logined in."); } @Override public void killBoss() { // TODO Auto-generated method stub System.out.println(this.name + " is killing his boss.."); } @Override public void upgrade() { // TODO Auto-generated method stub System.out.println(this.name + " uograded 1."); } } package com.proxyPattern; public class GamePlayerProxy implements IGamePlayer { IGamePlayer gamePlayer = null; public GamePlayerProxy(IGamePlayer gamePlayer) { this.gamePlayer = gamePlayer; } @Override public void login(String name, String password) { // TODO Auto-generated method stub this.gamePlayer.login(name, password); } @Override public void killBoss() { // TODO Auto-generated method stub this.gamePlayer.killBoss(); } @Override public void upgrade() { // TODO Auto-generated method stub this.gamePlayer.upgrade(); } } package com.proxyPattern; public class Client { public static void main(String[] args) { // TODO Auto-generated method stub IGamePlayer gamePlayer = new GamePlayer("Tom"); IGamePlayer proxy = new GamePlayerProxy(gamePlayer); proxy.login("Tom", "123"); proxy.killBoss(); proxy.upgrade(); //Another player IGamePlayer gamePlayer2 = new GamePlayer("Jack"); IGamePlayer proxy2 = new GamePlayerProxy(gamePlayer2); proxy2.login("Jack", "456"); proxy2.killBoss(); proxy2.upgrade(); } }
代理模式的擴展:
(一)普通代理
- 要求客戶端只能訪問代理角色,而不能訪問真實角色
(二)強制代理
- 不管是通過代理類還是通過直接new一個主題角色類,都不能訪問,只有通過真實角色指定的代理類才可以訪問
- Demo Coding:
-
package com.forceProxyPattern; public interface IGamePlayer { //玩家登陸 public void login(String name, String password); //打boss public void killBoss(); //升級 public void upgrade(); //每個人都有自己的代理 public IGamePlayer getProxy(); } package com.forceProxyPattern; public class GamePlayer implements IGamePlayer { private String name = ""; //我的代理 private IGamePlayer proxy = null; public GamePlayer(String name) { this.name = name; } @Override public void login(String name, String password) { // TODO Auto-generated method stub if(this.isProxy()) { System.out.println(this.name + " 登陸成功!"); } else { System.out.println("請使用指定的代理訪問"); } } @Override public void killBoss() { // TODO Auto-generated method stub if(this.isProxy()) { System.out.println(this.name + " 在打怪。"); } else { System.out.println("請使用指定的代理訪問"); } } private boolean isProxy() { // TODO Auto-generated method stub if(proxy == null) return false; else return true; } @Override public void upgrade() { // TODO Auto-generated method stub if(this.isProxy()) { System.out.println(this.name + " 又升一級!"); } else { System.out.println("請使用指定的代理訪問"); } } //找到自己的代理 @Override public IGamePlayer getProxy() { // TODO Auto-generated method stub this.proxy = new GamePlayerProxy(this); return this.proxy; } } package com.forceProxyPattern; public class GamePlayerProxy implements IGamePlayer { private IGamePlayer gamePlayer = null; public GamePlayerProxy(IGamePlayer gamePlayer) { this.gamePlayer = gamePlayer; } @Override public void login(String name, String password) { // TODO Auto-generated method stub this.gamePlayer.login(name, password); } @Override public void killBoss() { // TODO Auto-generated method stub this.gamePlayer.killBoss(); } @Override public void upgrade() { // TODO Auto-generated method stub this.gamePlayer.upgrade(); } @Override public IGamePlayer getProxy() { // TODO Auto-generated method stub return this; } } package com.forceProxyPattern; public class Client { public static void main(String[] args) { // TODO Auto-generated method stub //定義一個游戲的角色 IGamePlayer player = new GamePlayer("李四"); //獲得指定代理 IGamePlayer proxy = player.getProxy(); proxy.login("lisi", "123"); proxy.killBoss(); proxy.upgrade(); } }
(三)動態代理
- 動態代理在實現階段不關心代理誰,而在運行階段才指定代理哪一個對象;
- 一個非常流行的編程方式叫做面向橫切面編程(Aspect Oriented Programming-AOP),其核心就是采用了動態代理機制。
- Demo Coding:
-
public interface Subject { //業務操作 public void doSomething(String str); } public class RealSubject implements Subject { //具體的業務操作實現 public void doSomething(String str) { System.out.println("do something.."); } } //動態代理的Handler類 public class MyInvocationHandler implements InvocationHandler { //被代理的對象 private Object target = null; //通過構造函數傳遞一個對象 public MyInvocationHandler(Object target) { this.target = target; } //代理方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //執行被代理的方法 return method.invoke(this.target, args); } } public class Client { public static void main(String[] args) { // // TODO Auto-generated method stub //定義一個主題 Subject subject = new RealSubject(); //定義一個Handler InvocationHandler handler = new MyInvocationHandler(subject); //獲得類的class loader ClassLoader cl = subject.getClass().getClassLoader(); //動態產生一個代理者 Subject proxy = (Subject) Proxy.newProxyInstance(cl, new Class[]{Subject.class}, handler); proxy.doSomething("Finish"); } }
六。原型模式(Prototype Pattern)
Definition: Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
- 原型模式的核心是一個clone方法,通過該方法進行對象的拷貝,java提供了一個Cloneable接口來標識這個對象是可以拷貝的,JVM中只有這個標記的對象才有可能被拷貝;
- 原型模式通用代碼:
-
public class PrototypeClass implements Cloneable { //覆寫父類中的方法 @Override public PrototypeClass clone() { PrototypeClass prototypeClass = null; try { prototypeClass = (PrototypeClass) super.clone(); } catch(CloneNotSupportedException e) { e.printStackTrace(); } return prototypeClass; } }
-
- 優點:
- 原型模式是在內存二進制流的拷貝,比直接new一個對象性能好很多,特別是在一個循環體內產生大量對象的時候;
- 逃避構造函數的約束:直接在內存中拷貝,構造函數是不會被執行的。
- 使用場景:
- 資源優化場景:類初始化需要非常多的資源,包括數據、硬件資源等;
- 性能和安全要求的場景:用過new產生一個對象需要非常繁瑣的數據准備貨訪問權限,則可以使用原型模式;
- 一個對象多個修改者的場景:一個對象需要提供給其他對象訪問,而且各個調用者可能需要修改其值時。
- 在實際的項目中,原型模式一般與工廠模式一起出現,用過clone方法創建一個對象,然后由工廠方法提供給調用者。
- 深拷貝與淺拷貝:
- 淺拷貝:Object類提供的方法clone只是拷貝本對象,其對象內部的數組、引用對象等都不拷貝,還是指向原聲對象的呢哦不元素地址。(即拷貝的僅僅是內部對象的地址)
- 深拷貝:拷貝的是對象本身
- 二者分開使用
- final與clone的相愛相殺:若想使用clone,就不要加final關鍵字了。
(-------------------未完待續----------------------)