设计模式系列:模板方法模式和建造者模式

场景

当前有一套试题,总共有三道题目。现在小丽和亮亮要来答题。

  1. 2B铅笔的内芯是什么材质? a.铅 b.碳 c.石墨 答案:()
  2. 哪儿是世界上领土面积最大的国家? a.加拿大 b.俄罗斯 c.中国 d.德国 答案:()
  3. 谁是后世尊称的“药王”?a.僧一行 b.王叔和 c.李时珍 d.孙思邈 答案:()

第一版代码实现

 public class LiliQuersionAnswer {
    public void question1() {
        System.out.println("1. 2B铅笔的内芯是什么材质? a.铅 b.碳 c.石墨");
        System.out.println("答案:(C)");
    }
    public void question2() {
        System.out.println("2. 哪儿是世界上领土面积最大的国家? a.加拿大 b.俄罗斯 c.中国 d.德国");
        System.out.println("答案:(C)");
    }
    public void question3() {
        System.out.println("3. 谁是后世尊称的“药王”?a.僧一行 b.王叔和 c.李时珍 d.孙思邈");
        System.out.println("答案:(C)");
    }
}

上版问题在哪儿?

所有人的卷面是一样的,但答案是不同人答题结果不一样。以上写法,问题无法复用;

注意:如果你想用question做接口,那么意味着你将有3个question接口实现类,对应的丽利和亮亮对应的answer需要没人三个实现的answer实现类。这个是过度设计的。

第二版代码

public abstract class AbstractQuestionAnswer {
    public void question1(){
        System.out.println("1. 2B铅笔的内芯是什么材质? a.铅 b.碳 c.石墨");
        System.out.println("答案:(" + answer1()+")");
    }
    public void question2(){
        System.out.println("2. 哪儿是世界上领土面积最大的国家? a.加拿大 b.俄罗斯 c.中国 d.德国");
        System.out.println("答案:(" + answer2()+")");
    }
    public void question3() {
        System.out.println("3. 谁是后世尊称的“药王”?a.僧一行 b.王叔和 c.李时珍 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";}
}

模板方法

概念

利用继承的方式,将公用的部分放入父类中,子类实现非公用(特殊)的部分。相当于基类(父类)定义算法骨架,并且将一些公用的实现放入基类中。子类实现基础类的定义,当然,可以覆盖基类的protected/public非abstract方法。

类图

template-method.png

场景

女娲带着小美女们造人了。造了三种人:白种人、黄种人、黑种人。人都有手臂、鼻子、眼睛、头、身体、腿,请用代码实现白种人、黄种人和黑种人

第一版代码(Version1)

public class WhitePersonBuilder {
    public void build(){
        System.out.println("我有一双深邃的眼睛");
        System.out.println("我有一个高高的鼻梁");
        System.out.println("我的皮肤很白");
        System.out.println("我的手很长,手掌很大");
        System.out.println("我的腿很长");
    }
}

public class YellowPersonBuilder {

    public void build(){
        System.out.println("我有一双水灵的眼睛");
        System.out.println("我有一个可爱的鼻梁");
        System.out.println("我的皮肤是肉色");
        System.out.println("我的手很细长,手掌有特点");
        System.out.println("南边的腿是短的,北边的腿是长的");
    }
}

第一版代码(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("我的手很长,手掌很大");
    }
    public void buildFoot(Person person) {
        person.setFoot("我的腿很长");
    }
    public void buildEyes(Person person) {
        person.setEyes("我有一双深邃的眼睛");
    }
    public void buildNose(Person person) {
        person.setNose("我有一个高高的鼻梁");
    }
}

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("---------------");
    }
}

上版有问题吗?

version2的版本实现没有问题,相当于说你要给造个人,先给我个素材,然后按照模板方法做组装,有点像流水线上的汽车组装

第二版本代码

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("我的手长,只有掌心是白色的");
    }
    public void buildFoot() {
        person.setFoot("我的腿全是黑毛,但是,你察觉不到");
    }
    public void buildEye() {
        person.setEyes("我有一双深邃的眼睛");
    }
    public void buildNose() {
        person.setNose("我有一个粗短的鼻梁");
    }
    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("---------------");
    }
}

比较一下第二版实现和第一版(Version2)实现,有什么区别

  • 第二版支持美女们在不动IBuilder的实现类的情况下造出残疾人(无foot或无hand),怎么呢实现呢?
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)实现残疾人必须重新定义abstractBuilder,并重新依据abstractBuilder实现子类,以支持残疾人的构造

建造者模式

概念

将一个复杂的构建与表示分离,使得同样的构建过程,能有不一样的表示。

类图

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

比较区别

  1. 建造者是使用组合方式实现不同的表示,而模板方法使用的是继承的方式。组合优于继承。
  2. 建造者抽象的是构建过程,而模板方法提取的是实现公共。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容