设计模式:建造者模式学习---创建英雄

ps:android 中的设计模式:https://www.jianshu.com/p/1a9f571ad7c0

建造者模式,是指在创建一个复杂类型对象时,将创建过程和它的组成(表示)分离,使得同样的构建过程可以创建不同的表示。

在实际的开发中,有时候我们在创建对象的时候发现这个对象有很多的参数,为了涵盖所有的创建的模式,这个类需要包含每个参数的构造方法。比如:

public class TheObject(){

    private int o1;
    private int o2;
    private int o3;
    publiv TheObject(int o1){
    this.o1=o1;
    }   
    publiv TheObject(int o1,o2){
    this.o1=o1;
    this.o2=o2;
    }
    publiv TheObject(int o1,int o2,int o3){
    this.o1=o1;
    this.o2=o2;
    this.o3=o3;
    }
}

这里方法并没有定义完全,但是可以看到仅有三个变量,构造方法已经显得臃肿起来。当我们需要定义的参数更多,定义的方法更加复杂的时候,这会导致代码很难写,也很难阅读,而且在进行多线程编程的时候,例如在两个不同的线程中对同一个变量调用构造方法进行不同的实例化,由于线程执行的特性,会导致一些问题。

此时,构造者模式提供了一个解决这个问题的方法。

ps:显然之前的方法要比建造者模式容易理解,在平时编程也经常用之前的方法。

回顾一下建造者模式的概念:将一个复杂概念的创建过程和它的组成分离,那么意味着可以将创建过程写成接口,创建一个生产者,实现这些创建过程。而具体获得某种对象时,需要在指导者对象中具体调用相应的方法。下面通过一个实例来演示这个过程。

例子:创建英雄的过程 1.生产对象的描述:英雄们所拥有的属性有:生命值(HP),魔法值(SP),能量(Chakra),攻击力(Attack),法术强度(Magic),护甲值(Shell),魔法抗性(Magres),移动速度(Speed) 2.实际生产描述:在实际的英雄属性中,有的英雄没有魔法值,有的英雄没有魔法抗性,有的英雄有法术强度等情况,所以可以用建造者模式来实现英雄创建的功能。 3.需要创建的对象:英雄对象(class),构建方法(build 接口)其中有对应的构造方法,

英雄属性描述对象:

public class Hero{
    private float hp;//血量
    private float sp;//魔法值
    private float chakra;//能量
    private float attack;//攻击力
    private float magic;//法术强度
    private float shell;//护甲值
    private float magres;//魔法抗性
    private float speed;//移动速度

    //get和set方法省略
}

这里包含了所有英雄会有的属性。但其实这些属性在我们创建英雄时并不会全部用到。如果按照老的方法,要包含所有的构造可能性,需要重载许多个构造方法。但是我们采用构造者模式,则会使过程简单,使用方便。

接下来我们创建一个包含建造方法的接口:

public interface Builder {

    /*
     * 包含了产品 创建过程和返回产品的方法
     */
    public Builder BuildHp(float hp);
    public Builder BuildSp(float sp);
    public Builder BuildChakra(float chakra);
    public Builder BuildAttack(float attack);
    public Builder BuildMagic(float magic);
    public Builder BuildShell(float shell);
    public Builder BuildMagRes(float magRes);
    public Builder BuildSpeed(float speed);

    public Hero CreatHero();

}

其中包含了每个属性的建造方法,还包含了一个英雄创建方法。

现在英雄对象和创建方法都有了,接下来我们要创建一个生产者来实现这些建造方法

public class HeroGenerator implements Builder {
    Hero theHero;
    private float hp = 0;// 血量
    private float sp = 0;// 魔法值
    private float chakra = 0;// 能量
    private float attack = 0;// 攻击力
    private float magic = 0;// 法术强度
    private float shell = 0;// 护甲值
    private float magRes = 0;// 魔法抗性
    private float speed = 0;// 移动速度

    private static class SingletonHoder {
        private static final HeroGenerator generator = new HeroGenerator();
    }

    private HeroGenerator() {
        theHero = new Hero();
    }

    public static final HeroGenerator getInstance() {
        return SingletonHoder.generator;
    }

    @Override
    public Builder BuildHp(float hp) {
        // TODO Auto-generated method stub
        this.hp = hp;
        logger.info("生命值:" + hp);
        //System.out.println("生命值:" + hp);
        return this;
    }

    @Override
    public Builder BuildSp(float sp) {
        // TODO Auto-generated method stub
        this.sp = sp;
        logger.info("魔法值:" + sp);
        //System.out.println("魔法值:" + sp);
        return this;
    }

    @Override
    public Builder BuildChakra(float chakra) {
        // TODO Auto-generated method stub
        this.chakra = chakra;
        //System.out.println("能量值:" + chakra);
        logger.info("能量值:" + chakra);
        return this;
    }

    @Override
    public Builder BuildAttack(float attack) {
        // TODO Auto-generated method stub
        this.attack = attack;
        //System.out.println("攻击力:" + attack);
        logger.info("攻击力:" + attack);
        return this;
    }

    @Override
    public Builder BuildMagic(float magic) {
        // TODO Auto-generated method stub
        this.magic = magic;
        //System.out.println("法术强度:" + magic);
        logger.info("法术强度:" + magic);
        return this;
    }

    @Override
    public Builder BuildShell(float shell) {
        // TODO Auto-generated method stub
        this.shell = shell;
        //System.out.println("法术强度:" + magic);
        logger.info("法术强度:" + magic);
        return this;
    }

    @Override
    public Builder BuildMagRes(float magRes) {
        // TODO Auto-generated method stub
        this.magRes = magRes;
        //System.out.println("魔抗:" + magRes);
        logger.info("魔抗:" + magRes);
        return this;
    }

    @Override
    public Builder BuildSpeed(float speed) {
        // TODO Auto-generated method stub
        this.speed = speed;
        //System.out.println("移动速度:" + speed);
        logger.info("移动速度:" + speed);
        return this;
    }

    @Override
    public Hero CreatHero() {
        // TODO Auto-generated method stub
        theHero.setHp(hp);
        theHero.setSp(sp);
        theHero.setChakra(chakra);
        theHero.setAttack(attack);
        theHero.setMagic(magic);
        theHero.setShell(shell);
        theHero.setMagRes(magRes);
        theHero.setSpeed(speed);

        return this.theHero;
    }
}

在这个建造者类中,采用了单例模式来包装建造者的构造方法,关于单例模式,请看《Hi,我们再来聊一聊Java的单例吧》

实现构造方法的写法思想来源自《Effective Java 第二版》的第二条:遇到多个构造器参数是要考虑用构造器。在每个build方法中返回当前对象this,这种写法有个好处是可以将所有的调用链接起来,使得代码容易编写。

好了,现在我们就可以创建英雄了。现在请设计师出场,来设计每个英雄的属性。

public class Director {

    private HeroGenerator generator;

    public Director(HeroGenerator generator){
        this.generator = generator;
    }
    //创建卡特琳娜
    public Hero SommonKaterina() {

        System.out.println("召唤卡特琳娜");
        return generator.BuildHp(450).BuildAttack(55).BuildShell(25).BuildMagRes(27)
                .BuildSpeed(355).CreatHero();
    }
    //创建盖伦
    public Hero SommonGalen(){
        System.out.println("召唤盖伦");
        return generator.BuildHp(550).BuildAttack(68).BuildShell(33).BuildMagRes(36)
                .BuildSpeed(340).CreatHero();
    }
    //创建皇子
    public Hero SommonGarven(){
        System.out.println("召唤皇子");
        return generator.BuildHp(500).BuildSp(350).BuildAttack(68).BuildShell(31)
                .BuildMagRes(35).BuildSpeed(345).CreatHero();
    }
    //创建霞
    public Hero SommoXia(){
        System.out.println("召唤霞");
        return generator.BuildHp(450).BuildSp(400).BuildAttack(65).BuildShell(25).BuildMagRes(27)
                .BuildSpeed(350).CreatHero();
    }
    //创建洛
    public Hero SommoLuo(){
        System.out.println("召唤洛");
        return generator.BuildHp(500).BuildSp(375).BuildAttack(60).BuildShell(27).BuildMagRes(30)
                .BuildSpeed(350).CreatHero();
    }
}

这样构造,会使得代码编写十分方便整洁,而且十分灵活。

我们在召唤这些英雄中,只需要调用这个类型中的具体方法中就可以了,非常方便。

public class SummonerCanyon {

    static Logger logger = Logger.getLogger(SummonerCanyon.class);
    public  HeroGenerator generator;
    public  Director director;

    }

    public void SummoneHeros() {

        PropertyConfigurator.configure("../createHero/src/log4j.xml");
        logger.setLevel(Level.INFO);
        logger.info("召唤英雄");
        //用静态方式访问改静态方法
        generator = HeroGenerator.getInstance();
        director = new Director(generator);
        director.SommonGalen();
        director.SommonGarven();
        director.SommonKaterina();
        director.SommoXia();
        director.SommoLuo();

    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        SummonerCanyon canyon = new SummonerCanyon();
        canyon.SummoneHeros();
    }

点击运行,输出结果为(这里我采用了log4j日志来输出结果)

2018-07-13 12:06:44,017 INFO  com.createHero.SummonerCanyon.SummoneHeros:42 - 召唤英雄
召唤盖伦
2018-07-13 12:06:44,021 INFO  com.createHero.base.HeroGenerator.BuildHp:38 - 生命值:550.0
2018-07-13 12:06:44,021 INFO  com.createHero.base.HeroGenerator.BuildAttack:66 - 攻击力:68.0
2018-07-13 12:06:44,024 INFO  com.createHero.base.HeroGenerator.BuildShell:84 - 护甲值:33.0
2018-07-13 12:06:44,024 INFO  com.createHero.base.HeroGenerator.BuildMagRes:94 - 魔抗:36.0
2018-07-13 12:06:44,024 INFO  com.createHero.base.HeroGenerator.BuildSpeed:103 - 移动速度:340.0
召唤皇子
2018-07-13 12:06:44,024 INFO  com.createHero.base.HeroGenerator.BuildHp:38 - 生命值:500.0
2018-07-13 12:06:44,024 INFO  com.createHero.base.HeroGenerator.BuildSp:47 - 魔法值:350.0
2018-07-13 12:06:44,025 INFO  com.createHero.base.HeroGenerator.BuildAttack:66 - 攻击力:68.0
2018-07-13 12:06:44,025 INFO  com.createHero.base.HeroGenerator.BuildShell:84 - 护甲值:31.0
2018-07-13 12:06:44,025 INFO  com.createHero.base.HeroGenerator.BuildMagRes:94 - 魔抗:35.0
2018-07-13 12:06:44,025 INFO  com.createHero.base.HeroGenerator.BuildSpeed:103 - 移动速度:345.0
召唤卡特琳娜
2018-07-13 12:06:44,025 INFO  com.createHero.base.HeroGenerator.BuildHp:38 - 生命值:450.0
2018-07-13 12:06:44,025 INFO  com.createHero.base.HeroGenerator.BuildAttack:66 - 攻击力:55.0
2018-07-13 12:06:44,025 INFO  com.createHero.base.HeroGenerator.BuildShell:84 - 护甲值:25.0
2018-07-13 12:06:44,027 INFO  com.createHero.base.HeroGenerator.BuildMagRes:94 - 魔抗:27.0
2018-07-13 12:06:44,027 INFO  com.createHero.base.HeroGenerator.BuildSpeed:103 - 移动速度:355.0
召唤霞
2018-07-13 12:06:44,027 INFO  com.createHero.base.HeroGenerator.BuildHp:38 - 生命值:450.0
2018-07-13 12:06:44,028 INFO  com.createHero.base.HeroGenerator.BuildSp:47 - 魔法值:400.0
2018-07-13 12:06:44,028 INFO  com.createHero.base.HeroGenerator.BuildAttack:66 - 攻击力:65.0
2018-07-13 12:06:44,028 INFO  com.createHero.base.HeroGenerator.BuildShell:84 - 护甲值:25.0
2018-07-13 12:06:44,028 INFO  com.createHero.base.HeroGenerator.BuildMagRes:94 - 魔抗:27.0
2018-07-13 12:06:44,028 INFO  com.createHero.base.HeroGenerator.BuildSpeed:103 - 移动速度:350.0
召唤洛
2018-07-13 12:06:44,028 INFO  com.createHero.base.HeroGenerator.BuildHp:38 - 生命值:500.0
2018-07-13 12:06:44,028 INFO  com.createHero.base.HeroGenerator.BuildSp:47 - 魔法值:375.0
2018-07-13 12:06:44,028 INFO  com.createHero.base.HeroGenerator.BuildAttack:66 - 攻击力:60.0
2018-07-13 12:06:44,028 INFO  com.createHero.base.HeroGenerator.BuildShell:84 - 护甲值:27.0
2018-07-13 12:06:44,028 INFO  com.createHero.base.HeroGenerator.BuildMagRes:94 - 魔抗:30.0
2018-07-13 12:06:44,029 INFO  com.createHero.base.HeroGenerator.BuildSpeed:103 - 移动速度:350.0
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容