设计模式基础 建造者模式

定义及适用场景

建造者(Builder)模式,是一种创建型的设计模式。使用建造者这样一个名称命名它,是因为这个设计模式专注于对象复杂的建造过程。而非像工厂模式那般仅注意对象的产生。

它适用于类似生成游戏人物这样的场景。一个游戏人物,需要很多的步骤来完成设计,像基础数据设定,技能选择,生涯选择等等。

值得注意的是,这些都是构建人物对象的生产过程,而非人物对象本身。建造者模式的一个特点,便是它使得模型同其生产过程分离,减少了类的耦合性,增加了架构的灵活性。

因为这样一来,如何生产对象,如何将对象从new出的一个胚子逐步的点缀修饰,成为一个最终的产品,就变成了建造者需要实现的内容,而与对象类本身无关,这保证了产品本身同生产流程的解耦。

另外,一个对象如何生产,仅受建造者类控制。因此,如果需要改变或者新加对象的生产流程,仅需要更改建造者即可,它不影响场景使用,也不影响对象模型。这保证了设计的灵活性。


类的组成

建造者模式的实现,有赖于四个部分的组成,他们分别是:

  • product,产品类,是需要被创建的产品,包含多个需要被创建的部分。
  • Builder,抽象建造者类,负责制定抽象的产品生产方法,定义装配过程。
  • ConcreteBuilder,具体建造者类,它们是一种类,负责具体实现不同版本产品的各个装配具体流程。
  • Director,指导者类,也叫导演类,负责按照一定顺序调用建造者的方法,指导对象的生产,将产品最终生产出来。一般来说,导演类会聚合一个建造者类,但不与产品类发生关联。

下面,我们以一个场景作为体现。

场景需求

塔防游戏存在多种怪物,他们形象各异,属性不同,需要构建的部分包含图像和属性。现需要设计结构,使得在场景中方便创建对应怪物,同时需要便于增改怪物的构建。

我们选用建造者模式来完成这个设计。首先先完成类图的设计。

在这里插入图片描述

  • 产品类:Monster包含了基础属性和图像
  • 抽象建造者类:组合了一个产品类用于生产,制定了生产产品所需的几个步骤:获得胚子,设定属性,设定图像,完工出炉。
  • 具体建造者类:继承抽象建造者类,重写父类设定属性和设定图像的方法,以此建造不同类型的对象。
  • 导演类:内部聚合了一个生产者,作为生产产品的蓝图这个成员应该允许改变,以生产不同的产品。提供生产方法,用以指导建造者构建对象并返回成品。

完成这四个类的设计后,我们还需要在场景类中调用这些个类,那么加入场景类后,类图将变成:
在这里插入图片描述
可以看到,对于场景类来说,实现对象的创建并不需要与产品类产生依赖,仅需要使用导演类并为其指定生产蓝图(具体建造者类即可)


最终实现

下面,我们就可以根据刚刚的设计,将想法付诸实践了。为了方便演示,我们设定两种怪物:哥布林和暗夜骑士,并暂时将图像改做英雄出场台词。

java版本

产品类
public class Monster {
	
    private int HP;
    private int speed;
    private int damage;
    private String name;
    private String graph;
    
	public String getGraph() {
		return graph;
	}
	public void setGraph(String graph) {
		this.graph = graph;
	}
	public int getHP() {
		return HP;
	}
	public void setHP(int hP) {
		HP = hP;
	}
	public int getSpeed() {
		return speed;
	}
	public void setSpeed(int speed) {
		this.speed = speed;
	}
	public int getDamage() {
		return damage;
	}
	public void setDamage(int damage) {
		this.damage = damage;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
    
	public String toString() {
		return "name:" + name + ",HP:" + HP + ",speed:" + speed + ",damage:" + damage + "\n";
	}
}
抽象建造者类
abstract public class AbstractMonsterBuilder {

	protected Monster monster;
	
    abstract public void setAttribute();
    
    abstract public void setGraph();
    
    public Monster getMonster(){
        return monster;
    }
    
    public void getNew() {
    	monster = new Monster();
    }

}
具体建造者类

哥布林类

public class Monster1Builder extends AbstractMonsterBuilder {

   
	@Override
	public void setAttribute() {
		monster.setDamage(10);
		monster.setHP(100);
		monster.setName("哥布林");
		monster.setSpeed(50);
	}

	@Override
	public void setGraph() {
		monster.setGraph("哥布林冲锋!!!!!");
	}

}

暗夜骑士类

public class Monster2Builder extends AbstractMonsterBuilder {

	@Override
	public void setAttribute() {
		monster.setDamage(30);
		monster.setHP(200);
		monster.setName("暗夜骑士");
		monster.setSpeed(150);
	}

	@Override
	public void setGraph() {
		monster.setGraph("感受黑暗的铁蹄吧!!!!");
	}
}

导演类
public class MonsterBuildDirector {
	
    private AbstractMonsterBuilder builder;
    
    MonsterBuildDirector(AbstractMonsterBuilder builder){
    	setBuilder(builder);
    }
    
    public void setBuilder(AbstractMonsterBuilder builder) {
    	this.builder = builder;
    }

    public Monster Construct(){
    	
    	//获得胚子
    	builder.getNew();
    	//设置属性
    	builder.setAttribute();
    	//设置图像(开场白)
    	builder.setGraph();
    	//返回产品
        return builder.getMonster();
    }
}

为了便于导演类更换生产图纸,在类中添加了setBuilder方法以中途更换Builder

场景类
public class Client {
	static public void main(String[] args) {
		Monster monster = null;
		
		//初始化一个导演类对象,默认基于哥布林的生产图纸
		MonsterBuildDirector director = new MonsterBuildDirector(new Monster1Builder());
		
		//生产一个哥布林,并输出属性和开场白
		monster = director.Construct();
		System.out.print(monster);
		System.out.println(monster.getGraph());
		
		System.out.println("----------------------------------"); 
		//更改图纸为暗夜骑士
		director.setBuilder(new Monster2Builder());
		//生产一个暗夜骑士,并输出属性和开场白
		monster = director.Construct();
		System.out.print(monster);
		System.out.println(monster.getGraph());
		
	}
}
执行结果

在这里插入图片描述

C++版本

产品类
#ifndef MONSTER_H
#define MONSTER_H
class Monster
{
  public:
      Monster();
      
      string Getname() { return name; }
      void Setname(string val) { name = val; }
      int Getdamage() { return damage; }
      void Setdamage(int val) { damage = val; }
      int Getspeed() { return speed; }
      void Setspeed(int val) { speed = val; }
      int GetHP() { return HP; }
      void SetHP(int val) { HP = val; }
      string Getgraph() { return graph; }
      void Setgraph(string val) { graph = val; }
  private:
      string name;
      int damage;
      int speed;
      int HP;
      string graph;
};

#endif // MONSTER_H
抽象建造者类
#ifndef BUILDER_H
#define BUILDER_H
#include"Monster.h"
class Builder
{
    public:
        virtual ~Builder();

        Monster* getMonster(){return monster;}
        void getNew(){monster = new Monster();}

        virtual void setAttribute() = 0;
        virtual void setGraph() = 0;

    protected:
        Monster * monster;
};

#endif // BUILDER_H

具体建造者类

哥布林

#ifndef BUILDER_H
#define BUILDER_H
#include"Monster.h"
class Builder
{
    public:
        virtual ~Builder();

        Monster* getMonster(){return monster;}
        void getNew(){monster = new Monster();}

        virtual void setAttribute() = 0;
        virtual void setGraph() = 0;

    protected:
        Monster * monster;
};

#endif // BUILDER_H

#include "Monster1Builder.h"

void Monster1Builder::setAttribute()
{
    monster->Setname("哥布林");
    monster->Setdamage(10);
    monster->Setspeed(50);
    monster->SetHP(100);
}

void Monster1Builder::setGraph()
{
    monster->Setgraph("哥布林冲锋!!!!");
}


暗夜骑士

#ifndef MONSTER2BUILDER_H
#define MONSTER2BUILDER_H

#include <Builder.h>


class Monster2Builder : public Builder
{
    public:
        virtual void setAttribute();
        virtual void setGraph();
};

#endif // MONSTER2BUILDER_H

#include "Monster2Builder.h"

void Monster2Builder::setAttribute()
{
    monster->Setname("暗夜骑士");
    monster->Setdamage(30);
    monster->Setspeed(150);
    monster->SetHP(200);
}

void Monster2Builder::setGraph()
{
    monster->Setgraph("感受黑暗的铁蹄吧!!!!");
}


导演类
#ifndef DIRECTOR_H
#define DIRECTOR_H
#include"Builder.h"

class Director
{
    public:
        Director(Builder* builder):builder(builder){}
        ~Director();

        void Setbuilder(Builder* val) {
            delete builder;
            builder = val;
        }

        Monster* construct();
    private:
        Builder* builder;
};

#endif // DIRECTOR_H

#include "Director.h"

Director::~Director()
{
    delete builder;
}

Monster * Director::construct()
{
    builder->getNew();
    builder->setAttribute();
    builder->setGraph();
    return builder->getMonster();
}

场景
void Monster1Builder::setAttribute()
{
    monster->Setname("哥布林");
    monster->Setdamage(10);
    monster->Setspeed(50);
    monster->SetHP(100);
}

void Monster1Builder::setGraph()
{
    monster->Setgraph("哥布林冲锋!!!!");
}


执行结果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/wayne_lee_lwc/article/details/106658224