Java大话设计模式学习总结(十三)---建造者模式

建造者模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
来自大话设计模式
使用建造者模式的情景:
主要是用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。

建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。

举例:
当玩一个角色扮演类的游戏时,通常都需要创建一个角色,可以选择男性或女性,生成人物的打扮和武器也会根据选择的性别发生变化,但是男性和女性单独创建的流程都是固定不变的,即所有男性的打扮、武器都是固定的,这个生成角色的过程就可以用建造者模式实现。代码如下:

// Builder接口,用来定义构造对象需要的全部流程,并且有一个返回组装好的对象的方法
public interface IBuilder {
    public void buildSex();
    public void buildCloth();
    public void buildWeapon(); 
    public Person createPerson();
}

// 构建男性角色的类
public class BuildMan implements IBuilder {

    Person person;

    public BuildMan() {
        this.person = new Person();
    }

    @Override
    public void buildSex() {
        person.setSex("男");
        System.out.println("已选择男性角色进行创建");
    }

    @Override
    public void buildCloth() {
        person.setCloth("男性服饰");
        System.out.println("创建男性角色服装");
    }

    @Override
    public void buildWeapon() {
        person.setWeapon("男性武器");
        System.out.println("创建男性角色武器");
    }

    @Override
    public Person createPerson() {
        return this.person;
    }

}

// 构建女性角色的类
public class BuildWomen implements IBuilder {

    Person person;
    
    public BuildWomen() {
        this.person = new Person();
    }
    
    @Override
    public void buildSex() {
        person.setSex("女");
        System.out.println("已选择女性角色进行创建");
    }

    @Override
    public void buildCloth() {
        person.setCloth("女性服装");
       System.out.println("创建女性角色服装");
    }

    @Override
    public void buildWeapon() {
        person.setWeapon("女性武器");
        System.out.println("创建女性角色武器");
    }

    @Override
    public Person createPerson() {
        return this.person;
    }

}

// 角色类
public class Person {
    private String sex;
    private String cloth;
    private String weapon;
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public String getCloth() {
        return cloth;
    }
    public void setCloth(String cloth) {
        this.cloth = cloth;
    }
    public String getWeapon() {
        return weapon;
    }
    public void setWeapon(String weapon) {
        this.weapon = weapon;
    }
    public String show(){
        return "角色性别:" + sex + " 角色服饰:" + cloth + " 角色武器:" + weapon;
    }
}

是不是有的朋友会问,现在不是可以直接创建对象了吗?代码如下:

public class Test {
    public static void main(String[] args) {
        // 创建一个男性角色
        BuildMan man = new BuildMan();
        man.buildSex();
        man.buildCloth();
        man.buildWeapon();
        Person person1 = man.createPerson();
        System.out.println(person1.show());

        System.out.println("============");

        BuildWomen woman = new BuildWomen();
        woman.buildSex();
        woman.buildCloth();
        woman.buildWeapon();
        Person person2 = woman.createPerson();
        System.out.println(person2.show());
    }
}

仔细观察,所有生成角色的业务逻辑是一样的,必须要设置性别、服装和武器,少设置一个就会不符合业务逻辑。建造者模式就是把构造的流程放到一个专门指挥角色生成的对象中,由他负责去生成相应的属性,这样可以避免忘记生成某个属性,导致错误出现。下面添加这个指挥者类:

public class BuildDerector {
    public void BuildPerson(IBuilder builder) {
        builder.buildSex();
        builder.buildCloth();
        builder.buildWeapon();
    }
}

指挥者类只负责加工每个对象,不负责其他的业务逻辑。
下面看主程序类:

public class Test {
    public static void main(String[] args) {
        // 创建一个男性角色
        BuildDerector buildDerector = new BuildDerector();
        
        BuildMan man = new BuildMan();
        buildDerector.BuildPerson(man);
        Person person1 = man.createPerson();
        System.out.println(person1.show());
        
        System.out.println("============");
        
        BuildWomen woman = new BuildWomen();
        buildDerector.BuildPerson(woman);
        Person person2 = woman.createPerson();
        System.out.println(person2.show());
    }
}

结果如下:

已选择男性角色进行创建
创建男性角色服装
创建男性角色武器
角色性别:男 角色服饰:男性服饰 角色武器:男性武器
============
已选择女性角色进行创建
创建女性角色服装
创建女性角色武器
角色性别:女 角色服饰:女性服装 角色武器:女性武器

刚开始看的时候,我觉得建造者模式和模板模式十分相似,都是按照一个模板去实现业务逻辑,下面拿出来模板模式的主要代码:

// 体育运动模板类
public abstract class Sports {

    public void start(){
        System.out.println("比赛开始,开始计时。");
    }
    
    public void end(){
        System.out.println("时间到,比赛结束。");
    }
    
    public abstract void process();
    
    // 使用final修饰,防止修改模板
    public final void play(){
        start();
        process();
        end();
    }
}

public class Basketball extends Sports {
    @Override
    public void process() {
        System.out.println("开始进行篮球比赛");
    }
}

public class Test {
    public static void main(String[] args) {
        Sports sports = new Basketball();
        sports.play();
        System.out.println("=== another sport game ===");
        sports = new Football();
        sports.play();
    }
}

可以看出来,模板模式执行的业务逻辑都定义在了父类当中,所以每个子类都需要按照这个流程去执行。而建造者模式,虽然本次例子中,都是由同一个指挥者去执行,但指挥者类可以扩展出来子类,根据不同子类的建造者,采用不同的策略去执行,并且能保证同一个建造者实例化的对象执行的业务逻辑都相同,但是不同类的建造者实例化的对象执行的业务逻辑可以不相同

模板模式的使用情景:
每个子类的业务逻辑基本一样;很多代码可以进行复用;进行系统维护升级的情况下,可以采用模板模式进行向下兼容,通过增加钩子判断相应的版本以及执行的流程。

建造者模式的使用场景:
很多子类都需要执行相同的方法,但是存在顺序、逻辑不完全相同的情况

Write a class called Person with the following attributes: title (Mr., Mrs., Ms., etc.) first name last name nickname age in years sex (boolean - true/false to indicated either male or female) Write a constructor that takes no parameters and performs no initializations. Write a constructor that takes a parameter for each of the attributes listed above and sets them within the objects by calling the setter methods listed below. The Person class should have a setter method and a getter method with public access for each attribute. In the setter methods, get rid of any leading or trailing spaces (String trim() method). For a Person with the following attributes: title = "Mr." first name = "Michael" last name = "Zheng" nickname = "Mike" age = 22 sex = true (true is male, false is female) The Person class should have the following public access methods that return Strings as follows: standardName() concatenation of the first and last names (i.e., "Michael Zheng") formalName() concatenation of the title, first name, lastname (i.e., "Mr. Michael Zheng") casualName() return the nickname if it is not null, otherwise return the first name (i.e., "Mike") Be realistic when generating names. If a particular attribute does not exist for a given person, don't try to concatenate it. If necessary, add appropriate spacing and punctuation, but do not leave any leading or trailing spaces in the String that is returned. MakePerson Write a class called MakePerson with a main() method that instantiates 2 Person objects. Initialize the attributes of one of the Person objects by supplying parameters to it's constructor. Instantiate the other Person object with the default constructor (that does not accept any parameters), then set it's attributes via the appropriate setter methods. For each of the Person objects, execute and print (System.out.println()) the results of all of the getter methods and of the standardName(), formalName(), and casualName() methods.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值