設(shè)計(jì)模式系列:模板方法模式和建造者模式

場(chǎng)景

當(dāng)前有一套試題,總共有三道題目。現(xiàn)在小麗和亮亮要來(lái)答題。

  1. 2B鉛筆的內(nèi)芯是什么材質(zhì)? a.鉛 b.碳 c.石墨 答案:()
  2. 哪兒是世界上領(lǐng)土面積最大的國(guó)家? a.加拿大 b.俄羅斯 c.中國(guó) d.德國(guó) 答案:()
  3. 誰(shuí)是后世尊稱的“藥王”?a.僧一行 b.王叔和 c.李時(shí)珍 d.孫思邈 答案:()

第一版代碼實(shí)現(xiàn)

 public class LiliQuersionAnswer {
    public void question1() {
        System.out.println("1. 2B鉛筆的內(nèi)芯是什么材質(zhì)? a.鉛 b.碳 c.石墨");
        System.out.println("答案:(C)");
    }
    public void question2() {
        System.out.println("2. 哪兒是世界上領(lǐng)土面積最大的國(guó)家? a.加拿大 b.俄羅斯 c.中國(guó) d.德國(guó)");
        System.out.println("答案:(C)");
    }
    public void question3() {
        System.out.println("3. 誰(shuí)是后世尊稱的“藥王”?a.僧一行 b.王叔和 c.李時(shí)珍 d.孫思邈");
        System.out.println("答案:(C)");
    }
}

上版問(wèn)題在哪兒?

所有人的卷面是一樣的,但答案是不同人答題結(jié)果不一樣。以上寫法,問(wèn)題無(wú)法復(fù)用;

注意:如果你想用question做接口,那么意味著你將有3個(gè)question接口實(shí)現(xiàn)類,對(duì)應(yīng)的麗利和亮亮對(duì)應(yīng)的answer需要沒(méi)人三個(gè)實(shí)現(xiàn)的answer實(shí)現(xiàn)類。這個(gè)是過(guò)度設(shè)計(jì)的。

第二版代碼

public abstract class AbstractQuestionAnswer {
    public void question1(){
        System.out.println("1. 2B鉛筆的內(nèi)芯是什么材質(zhì)? a.鉛 b.碳 c.石墨");
        System.out.println("答案:(" + answer1()+")");
    }
    public void question2(){
        System.out.println("2. 哪兒是世界上領(lǐng)土面積最大的國(guó)家? a.加拿大 b.俄羅斯 c.中國(guó) d.德國(guó)");
        System.out.println("答案:(" + answer2()+")");
    }
    public void question3() {
        System.out.println("3. 誰(shuí)是后世尊稱的“藥王”?a.僧一行 b.王叔和 c.李時(shí)珍 d.孫思邈");
        System.out.println("答案:(" + answer3()+")");
    }
    public abstract String  answer1();
    public abstract String  answer2();
    public abstract String  answer3();
}
public class DefaultQuestionAnswer extends AbstractQuestionAnswer {
    public String answer1() {return "";}
    public String answer2() {return "";}
    public String answer3() {return "";}
}
public class PersonLiliQuestionAnswer extends DefaultQuestionAnswer {
    public String answer1() {return "c";}
![template-method.png](http://upload-images.jianshu.io/upload_images/6379913-668f5e9f44124153.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    public String answer2() {return "c";}
    public String answer3() {return "c";}
}

模板方法

概念

利用繼承的方式,將公用的部分放入父類中,子類實(shí)現(xiàn)非公用(特殊)的部分。相當(dāng)于基類(父類)定義算法骨架,并且將一些公用的實(shí)現(xiàn)放入基類中。子類實(shí)現(xiàn)基礎(chǔ)類的定義,當(dāng)然,可以覆蓋基類的protected/public非abstract方法。

類圖

template-method.png

場(chǎng)景

女媧帶著小美女們?cè)烊肆?。造了三種人:白種人、黃種人、黑種人。人都有手臂、鼻子、眼睛、頭、身體、腿,請(qǐng)用代碼實(shí)現(xiàn)白種人、黃種人和黑種人

第一版代碼(Version1)

public class WhitePersonBuilder {
    public void build(){
        System.out.println("我有一雙深邃的眼睛");
        System.out.println("我有一個(gè)高高的鼻梁");
        System.out.println("我的皮膚很白");
        System.out.println("我的手很長(zhǎng),手掌很大");
        System.out.println("我的腿很長(zhǎng)");
    }
}

public class YellowPersonBuilder {

    public void build(){
        System.out.println("我有一雙水靈的眼睛");
        System.out.println("我有一個(gè)可愛(ài)的鼻梁");
        System.out.println("我的皮膚是肉色");
        System.out.println("我的手很細(xì)長(zhǎng),手掌有特點(diǎn)");
        System.out.println("南邊的腿是短的,北邊的腿是長(zhǎng)的");
    }
}

第一版代碼(Version2)

public abstract class AbstractBuilder {
    public void build(Person person) {
        buildEyes(person);
        buildNose(person);
        buildHead(person);
        buildHand(person);
        buildFoot(person);
    }
    protected abstract void buildNose(Person person);
    protected abstract void buildEyes(Person person);
    protected abstract void buildHead(Person person);
    protected abstract void buildHand(Person person);
    protected abstract void buildFoot(Person person);
}

public class WhitePersonBuilder extends AbstractBuilder {
    public void buildHead(Person person) {
        person.setHead("我的皮膚很白");
    }
    public void buildHand(Person person) {
        person.setHand("我的手很長(zhǎng),手掌很大");
    }
    public void buildFoot(Person person) {
        person.setFoot("我的腿很長(zhǎng)");
    }
    public void buildEyes(Person person) {
        person.setEyes("我有一雙深邃的眼睛");
    }
    public void buildNose(Person person) {
        person.setNose("我有一個(gè)高高的鼻梁");
    }
}

public class Test {
 public static void main(String[] args){
       Person whitePerson = new Person();
       Person yellowPerson = new Person();
       Person blackPerson = new Person();
       AbstractBuilder whiteBuilder = new WhitePersonBuilder();
        AbstractBuilder yellowBuilder = new YellowPersonBuilder();
        AbstractBuilder blackBuilder = new BlackPersonBuilder();
        whiteBuilder.build(whitePerson);
        yellowBuilder.build(yellowPerson);
        blackBuilder.build(blackPerson);
        printPerson(whitePerson);
        printPerson(yellowPerson);
        printPerson(blackPerson);
    }
    private static void printPerson(Person blackPerson) {
        System.out.println("eyes:"+blackPerson.getEyes());
        System.out.println("nose:"+blackPerson.getNose());
        System.out.println("head:"+blackPerson.getHead());
        System.out.println("hand:"+blackPerson.getHand());
        System.out.println("foot:"+blackPerson.getFoot());
        System.out.println("---------------");
    }
}

上版有問(wèn)題嗎?

version2的版本實(shí)現(xiàn)沒(méi)有問(wèn)題,相當(dāng)于說(shuō)你要給造個(gè)人,先給我個(gè)素材,然后按照模板方法做組裝,有點(diǎn)像流水線上的汽車組裝

第二版本代碼

public interface IPersonBuilder {
    public void buildHead();
    public void buildHand();
    public void buildFoot();
    public void buildEye();
    public void buildNose();
    public Person getResult();
}

public class BlackPersonBuilder implements IPersonBuilder {
    private Person person = new Person();
    public void buildHead() {
        person.setHead("我的皮膚很黑");
    }
    public void buildHand() {
        person.setHand("我的手長(zhǎng),只有掌心是白色的");
    }
    public void buildFoot() {
        person.setFoot("我的腿全是黑毛,但是,你察覺(jué)不到");
    }
    public void buildEye() {
        person.setEyes("我有一雙深邃的眼睛");
    }
    public void buildNose() {
        person.setNose("我有一個(gè)粗短的鼻梁");
    }
    public Person getResult() {
        return person;
    }
}

public class Director {
    public void constructor(IPersonBuilder personBuilder){
        personBuilder.buildHead();
        personBuilder.buildEye();
        personBuilder.buildNose();
        personBuilder.buildHand();
        personBuilder.buildFoot();
    }
 }

public class Test {
    public static void main(String[] args){
        IPersonBuilder whitePersonBuilder = new WhitePersonBuilder();
        IPersonBuilder yellowPersonBuilder = new YellowPersonBuilder();
        IPersonBuilder blackPersonBuilder = new BlackPersonBuilder();
        Director director = new Director();
        director.constructor(whitePersonBuilder);
        director.constructor(yellowPersonBuilder);
        director.constructor(blackPersonBuilder);
        Person whitePerson = whitePersonBuilder.getResult();
        Person yellowPerson = yellowPersonBuilder.getResult();
        Person blackPerson = blackPersonBuilder.getResult();
        printPerson(whitePerson);
        printPerson(yellowPerson);
        printPerson(blackPerson);
    }
    private static void printPerson(Person blackPerson) {
        System.out.println("eyes:"+blackPerson.getEyes());
        System.out.println("nose:"+blackPerson.getNose());
        System.out.println("head:"+blackPerson.getHead());
        System.out.println("hand:"+blackPerson.getHand());
        System.out.println("foot:"+blackPerson.getFoot());
        System.out.println("---------------");
    }
}

比較一下第二版實(shí)現(xiàn)和第一版(Version2)實(shí)現(xiàn),有什么區(qū)別

  • 第二版支持美女們?cè)诓粍?dòng)IBuilder的實(shí)現(xiàn)類的情況下造出殘疾人(無(wú)foot或無(wú)hand),怎么呢實(shí)現(xiàn)呢?
public class DisableDirector {
    public void constructor(IPersonBuilder personBuilder){
        personBuilder.buildHead();
        personBuilder.buildEye();
        personBuilder.buildNose();
        // personBuilder.buildHand();
        // personBuilder.buildFoot();
    }
 }

public class Test {
    public static void main(String[] args){
        IPersonBuilder whitePersonBuilder = new WhitePersonBuilder();
        IPersonBuilder yellowPersonBuilder = new YellowPersonBuilder();
        IPersonBuilder blackPersonBuilder = new BlackPersonBuilder();
        //殘疾人組裝類
        Director director = new DisableDirector();
        director.constructor(whitePersonBuilder);
        director.constructor(yellowPersonBuilder);
        director.constructor(blackPersonBuilder);
        Person whitePerson = whitePersonBuilder.getResult();
        Person yellowPerson = yellowPersonBuilder.getResult();
        Person blackPerson = blackPersonBuilder.getResult();
        printPerson(whitePerson);
        printPerson(yellowPerson);
        printPerson(blackPerson);
    }
    private static void printPerson(Person blackPerson) {
        System.out.println("eyes:"+blackPerson.getEyes());
        System.out.println("nose:"+blackPerson.getNose());
        System.out.println("head:"+blackPerson.getHead());
        System.out.println("hand:"+blackPerson.getHand());
        System.out.println("foot:"+blackPerson.getFoot());
        System.out.println("---------------");
    }
}
  • 第一版(version2)實(shí)現(xiàn)殘疾人必須重新定義abstractBuilder,并重新依據(jù)abstractBuilder實(shí)現(xiàn)子類,以支持殘疾人的構(gòu)造

建造者模式

概念

將一個(gè)復(fù)雜的構(gòu)建與表示分離,使得同樣的構(gòu)建過(guò)程,能有不一樣的表示。

類圖

屏幕快照 2017-06-09 下午9.58.40.png

比較區(qū)別

  1. 建造者是使用組合方式實(shí)現(xiàn)不同的表示,而模板方法使用的是繼承的方式。組合優(yōu)于繼承。
  2. 建造者抽象的是構(gòu)建過(guò)程,而模板方法提取的是實(shí)現(xiàn)公共。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容