分類  >  編程 >

模板方式2

tags:    時間:2013-12-23 08:49:06
模板模式2

16.2  解決方案

16.2.1  模板方法模式來解決

用來解決上述問題的一個合理的解決方案就是模板方法模式。那麼什麼是模板方法模式呢?

(1)模板方法模式定義

 

(2)應用模板方法模式來解決的思路

       仔細分析上面的問題,重複或相似代碼太多、擴展不方便,出現這些問題的原因在哪裡?主要就是兩個實現是完全分開、相互獨立的,沒有從整體上進行控制。如果把兩個模塊合起來看,就會發現,那些重複或相似的代碼就應該被抽取出來,做成公共的功能,而不同的登錄控制就可以去擴展這些公共的功能。這樣一來,擴展的時候,如果出現有相同的功能,那就直接擴展公共功能就可以了。

       使用模板方法模式,就可以很好的來實現上面的思路。分析上面兩個登錄控制模塊,會發現它們在實現上,有著大致相同的步驟,只是在每步具體的實現上,略微有些不同,因此,可以把這些運算步驟看作是演算法的骨架,把具體的不同的步驟實現,延遲到子類去實現,這樣就可以通過子類來提供不同的功能實現了。

       經過分析總結,登錄控制大致的邏輯判斷步驟如下:

  • 根據登錄人員的編號去獲取相應的數據
  • 獲取對登錄人員填寫的密碼數據進行加密后的數據,如果不需要加密,那就是直接返回登錄人員填寫的密碼數據
  • 判斷登錄人員填寫的數據和從資料庫中獲取的數據是否匹配

在這三個步驟裡面,第一個和第三個步驟是必不可少的,而第二個步驟是可選的。那麼就可以定義一個父類,在裡面定義一個方法來定義這個演算法骨架,這個方法就是模板方法,然後把父類無法確定的實現,延遲到具體的子類來實現就可以了。

       通過這樣的方式,如果要修改加密的演算法,那就在模板的子類裡面重新覆蓋實現加密的方法就好了,完全不需要去改變父類的演算法結構,就可以重新定義這些特定的步驟。

16.2.2  模式結構和說明

模板方法模式的結構如圖16.1所示:

 

圖16.1  模板方法模式的結構示意圖

AbstractClass

       抽象類。用來定義演算法骨架和原語操作,具體的子類通過重定義這些原語操作來實現一個演算法的各個步驟。在這個類裡面,還可以提供演算法中通用的實現。

ConcreteClass

       具體實現類。用來實現演算法骨架中的某些步驟,完成跟特定子類相關的功能。

16.2.3  模板方法模式示例代碼

(1)先來看看AbstractClass的寫法,示例代碼如下:

/**

 * 定義模板方法、原語操作等的抽象類

 */

public abstract class AbstractClass {

    /**

     * 原語操作1,所謂原語操作就是抽象的操作,必須要由子類提供實現

     */

    public abstract void doPrimitiveOperation1();

    /**

     * 原語操作2

     */

    public abstract void doPrimitiveOperation2();

    /**

     * 模板方法,定義演算法骨架

     */

    public final void templateMethod() {

       doPrimitiveOperation1();

       doPrimitiveOperation2();

    }

}

(2)再看看具體實現類的寫法,示例代碼如下:

/**

 * 具體實現類,實現原語操作

 */

public class ConcreteClass extends AbstractClass {

    public void doPrimitiveOperation1() {

       //具體的實現

    }

    public void doPrimitiveOperation2() {

       //具體的實現

    }

}

16.2.4  使用模板方法模式重寫示例

要使用模板方法模式來實現前面的示例,按照模板方法模式的定義和結構,需要定義出一個抽象的父類,在這個父類裡面定義模板方法,這個模板方法應該實現進行登錄控制的整體的演算法步驟。當然公共的功能,就放到這個父類去實現,而這個父類無法決定的功能,就延遲到子類去實現。

這樣一來,兩種登錄控制就做為這個父類的子類,分別實現自己需要的功能。此時系統的結構如圖16.2所示:

 

圖16.2  使用模板方法模式實現示例的結構示意圖

(1)為了把原來的兩種登錄控制統一起來,首先需要把封裝登錄控制所需要的數據模型統一起來,不再區分是用戶編號還是工作人員編號,而是統一稱為登錄人員的編號,還有把其它用不上的數據去掉,這樣就直接使用一個數據模型就可以了。當然,如果各個子類實現需要其它的數據,還可以自行擴展。示例代碼如下:

/**

 * 封裝進行登錄控制所需要的數據

 */

public class LoginModel {

    /**

     * 登錄人員的編號,通用的,可能是用戶編號,也可能是工作人員編號

     */

    private String loginId;

    /**

     * 登錄的密碼

     */

    private String pwd;

    public String getLoginId() {

       return loginId;

    }

    public void setLoginId(String loginId) {

       this.loginId = loginId;

    }

    public String getPwd() {

       return pwd;

    }

    public void setPwd(String pwd) {

       this.pwd = pwd;

    }  

}

(2)接下來定義公共的登錄控制演算法骨架,示例代碼如下:

/**

 *  登錄控制的模板

 */

public abstract class LoginTemplate {

    /**

     * 判斷登錄數據是否正確,也就是是否能登錄成功

     * @param lm 封裝登錄數據的Model

     * @return true表示登錄成功,false表示登錄失敗

     */

    public final boolean login(LoginModel lm){

       //1:根據登錄人員的編號去獲取相應的數據

       LoginModel dbLm = this.findLoginUser(lm.getLoginId());

       if(dbLm!=null){

           //2:對密碼進行加密

           String encryptPwd = this.encryptPwd(lm.getPwd());

           //把加密后的密碼設置回到登錄數據模型裡面

           lm.setPwd(encryptPwd);

           //3:判斷是否匹配

           return this.match(lm, dbLm);

       }

       return false;

    }

    /**

     * 根據登錄編號來查找和獲取存儲中相應的數據

     * @param loginId 登錄編號

     * @return 登錄編號在存儲中相對應的數據

     */

    public abstract LoginModel findLoginUser(String loginId);

    /**

     * 對密碼數據進行加密

     * @param pwd 密碼數據

     * @return 加密后的密碼數據

     */

    public String encryptPwd(String pwd){

       return pwd;

    }

    /**

     * 判斷用戶填寫的登錄數據和存儲中對應的數據是否匹配得上

     * @param lm 用戶填寫的登錄數據

     * @param dbLm 在存儲中對應的數據

     * @return true表示匹配成功,false表示匹配失敗

     */

    public boolean match(LoginModel lm,LoginModel dbLm){

       if(lm.getLoginId().equals(dbLm.getLoginId())

              && lm.getPwd().equals(dbLm.getPwd())){

           return true;

       }

       return false;

    }

}

(3)實現新的普通用戶登錄控制的邏輯處理,示例代碼如下:

/**

 * 普通用戶登錄控制的邏輯處理

 */

public class NormalLogin extends LoginTemplate{

    public LoginModel findLoginUser(String loginId) {

       // 這裡省略具體的處理,僅做示意,返回一個有默認數據的對象

       LoginModel lm = new LoginModel();

       lm.setLoginId(loginId);

       lm.setPwd("testpwd");

       return lm;

    }

}

(4)實現新的工作人員登錄控制的邏輯處理,示例代碼如下:

/**

 * 工作人員登錄控制的邏輯處理

 */

public class WorkerLogin extends LoginTemplate{

    public LoginModel findLoginUser(String loginId) {

       // 這裡省略具體的處理,僅做示意,返回一個有默認數據的對象

       LoginModel lm = new LoginModel();

       lm.setLoginId(loginId);

       lm.setPwd("workerpwd");

       return lm;

    }

 

    public String encryptPwd(String pwd){

       //覆蓋父類的方法,提供真正的加密實現

       //這裡對密碼進行加密,比如使用:MD5、3DES等等,省略了

       System.out.println("使用MD5進行密碼加密");

       return pwd;

    }

}

       通過上面的示例,可以看出來,把原來的實現改成使用模板方法模式來實現,也並不困難,寫個客戶端測試一下,以便更好的體會,示例代碼如下:

public class Client {

    public static void main(String[] args) {

       //準備登錄人的信息

       LoginModel lm = new LoginModel();

       lm.setLoginId("admin");

       lm.setPwd("workerpwd");

 

       //準備用來進行判斷的對象

       LoginTemplate lt = new WorkerLogin();

       LoginTemplate lt2 = new NormalLogin();

 

       //進行登錄測試

       boolean flag = lt.login(lm);

       System.out.println("可以登錄工作平台="+flag);

      

       boolean flag2 = lt2.login(lm);

       System.out.println("可以進行普通人員登錄="+flag2);

    }

}

       運行結果示例如下:

使用MD5進行密碼加密

可以登錄工作平台=true

可以進行普通人員登錄=false

       當然,你可以使用不同的測試數據來測試這個示例。

推薦閱讀文章

Bookmark the permalink ,來源:互聯網