《大设》第十五篇之建造者模式

前言

国际惯例,本文仍然是在学习设计模式的路上所写,希望对同样在学习设计模式的童靴有点作用,大牛误入的话还请给点宝贵意见,感激不尽。

定义

百度百科

将一个复杂对象的构造和它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为构建者模式。

个人拙见

创建者模式是一个创建型的模式,本质是用来创建一个对象,但是并不是简单的使用new来创建一个对象,因为这个需要创建的对象所属的类型比较复杂,要创建的对象中包含有很多的组件,并且需要创建表现不同的该类型的对象,这时候如果在客户端直接使用new操作符创建对象,并且设置对象的属性可能会由于各种原因缺少或者设置错误对象中的属性,并且在创建多个相同对象时需要有重复代码,为了解决这个问题,创建者模式应运而生,建造者模式通过使用具体建造类实现抽象建造类的方式规定了要生成的对象中必须有的组件或者属性,然后使用指挥类指挥建造者类创建对象,并且通过不同的构建类利用多态的方式达到相同的构建过程不同的表示的目的,这就是创建者模式。

类图

《大设》第十五篇之建造者模式

建造者模式中的主要角色:

  1. 产品角色:要创建的复杂对象;
  2. 抽象构建类:规定了要生成的产品中的组件,约束具体的构建类,提供抽象接口;
  3. 具体构建类:实现抽象构建类,在具体构建类中构建要生成的产品的各个组件或者属性,还需要有一个返回生成的产品的方法来返回生成的产品;
  4. 指挥者类:持有一个构建类对象,指挥产品的构建过程;

代码实现

相信很多朋友没事的时候都喜欢撸一把,今天我们就使用建造者模式创建一个新的英雄,首先需要有一个英雄类(省略了属性的get/set方法,太占地方了):

public class Hero {

    private String name;
    private String passiveSkill;
    private String qSkill;
    private String wSkill;
    private String eSkill;
    private String rSkill;
    
    public Hero(String name){
        this.name = name;
    }
    
    //get/set方法省略

    @Override
    public String toString() {
        return "Hero [name=" + name + ", passiveSkill=" + passiveSkill + ", qSkill=" + qSkill + ", wSkill=" + wSkill
                + ", eSkill=" + eSkill + ", rSkill=" + rSkill + "]";
    }
}

然后是Bulider类,这是抽象构建类:

public interface HeroBulider {
    public void bulidPassiveSkill();
    public void bulidQSkill();
    public void bulidWSkill();
    public void bulidESkill();
    public void bulidRSkill();
    public Hero getHero();
}

具体的构建类,实现抽象构建类接口,进行具体的构建过程:

public class ConcreteHeroBulider implements HeroBulider{

    private Hero hero;
    
    public ConcreteHeroBulider(String heroName){
        hero = new Hero(heroName);
    }
    
    @Override
    public void bulidPassiveSkill() {
        hero.setPassiveSkill("回复");
        System.out.println(hero.getName()+"被动技能已设置");
    }

    @Override
    public void bulidQSkill() {
        hero.setqSkill("草丛剑");
        System.out.println(hero.getName()+"Q技能已设置");
    }

    @Override
    public void bulidWSkill() {
        hero.setwSkill("护甲");
        System.out.println(hero.getName()+"W技能已设置");
    }

    @Override
    public void bulidESkill() {
        hero.seteSkill("风火轮");
        System.out.println(hero.getName()+"E技能已设置");
    }

    @Override
    public void bulidRSkill() {
        hero.setrSkill("大保健");
        System.out.println(hero.getName()+"R技能已设置");
    }

    @Override
    public Hero getHero() {
        return this.hero;
    }
}

然后就是指挥者类了,指挥具体的创建过程:

public class Director {

    private HeroBulider bulider;
    
    public Director(HeroBulider bulider){
        this.bulider = bulider;
    }
    
    public Hero create(){
        bulider.bulidPassiveSkill();
        bulider.bulidQSkill();
        bulider.bulidWSkill();
        bulider.bulidESkill();
        bulider.bulidRSkill();
        return bulider.getHero();
    }
}

测试类:

public static void main(String[] args) {
    HeroBulider hb = new ConcreteHeroBulider("盖伦");
    Director director = new Director(hb);
    Hero hero = director.create();
    System.out.println(hero);
}

估计看完上面的具体构建者类有些朋友就知道我说的英雄是谁了,献丑献丑,请原谅我八百年才去打一把LOL的人不知道某个转转转的英雄的技能名字,只能这么写了。

测试结果:

《大设》第十五篇之建造者模式

上面是我们使用创建者模式的创建方式,那么如果不使用创建者模式怎么创建这个英雄对象呢,代码如下:

Hero hero1 = new Hero("皇子");
    hero1.setPassiveSkill("被动");
    hero1.setqSkill("q");
    hero1.setwSkill("w");
    hero1.seteSkill("e");
    hero1.setrSkill("r");
    System.out.println(hero1);

有的朋友可能会说,这不也没问题吗?何必再用个设计模式,搞的那么复杂还多写那么多代码,这个,兄弟,你还是太年轻了,说设计模式好就是设计模式好,管那么多干嘛?当然这只是开个玩笑,关于这个问题呢,要明白几点,首先,我们现在的hero对象很简单,只有四五个属性,但是如果是四五十个属性呢,你一个一个的去set不得累死啊,最重要的是很可能会少设置几个属性,你试试给LOL某个英雄少个技能,看看会不会被喷死,其次,每创建一个对象都需要重新set一遍这些属性,重复代码太多,就算IDE一屏能放下,还占电脑内存呢,该节省的地方我们还是要节省的,第三,如果对于一个对象需要多创建几次,那就得将set的代码复制好几次,占地方而且不好看。

优缺点

优点

  1. 建造者模式的封装性很好,使用建造者模式时产品类和具体的构建类是相对稳定的,因此,将产品的构建过程封装在指挥者类中,有利于提高产品的稳定性;
  2. 良好的扩展性,如果有新的构建方式,可以实现抽象的构建类,不必修改原来的代码,符合开闭原则;
  3. 产品的构建过程和产品本身分离开来,可以使用相同的构建过程生成不同的产品,也就是细节依赖抽象;

缺点

  1. 使用创建者模式创建的产品,其组成部分相似度很大,如果产品之间的差异性很大,那么就没法使用创建者模式,因此其使用范围受到一定的限制;
  2. 如果产品内部变化复杂,可能会导致需要定义很多具体创建者类来实现这种变化,导致系统很庞大。

扩展

如果建造者模式中的具体构建者只有一个,那么就可以省略掉抽象的构建者,在指挥者类中直接持有具体构建者类即可;

基于上述的扩展,如果具体构建者只有一个且省略了抽象构建者,那么指挥者类也可以省略掉,让具体构建者同时扮演构建者和指挥者两个角色;

(这里本来想在java中找到一些源码支持的,奈何读过的源码太少,实在找不到,以后遇到了再补充吧,有知道的大神请给个提示吧!!!)

与工厂模式的区别

  1. 工厂模式实际上是封装了new的过程,即在客户端不必再通过new的方式创建产品对象,而建造者模式实际上是让客户端在创建复杂对象时不必再去关注这个对象的创建过程,或者说是设置其中组件的过程;
  2. 建造者模式返回的是一个组装好的完整对象,但是工厂模式返回的是一系列相关的产品,这一系列产品可以构成一个产品族;
  3. 在工厂方法模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,但是在建造者模式中客户端通过实例化指挥者类,通过指挥者类来返回一个完整产品,并不需要关心建造者类的任何信息;

总结

建造者模式是一个创建型的设计模式,主要用以生成复杂的产品对象,并且将对象的创建过程和表示进行分离,使得同样的创建过程可以创建不同的表示。创建者模式常用语创建一批构建过程相同但是表示不同的产品,并且这个产品的构建过程十分复杂,至于是否要选择这个设计模式则取决于各个产品的构建过程是否相同,需要把握好产品的具体表示;

参考文章

  1. http://www.cnblogs.com/zuoxiaolong/p/pattern16.html
  2. http://blog.csdn.net/xiaodan007/article/details/7006431
  3. http://blog.csdn.net/zhang31jian/article/details/50538407

相关推荐