• 设计模式之生成器(Builder)模式


    意图

    将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以表示不同的表示。

    适用性

    • 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
    • 当构造过程必须允许被构造的对象有不同的表示时。

    UML图

    • Builder ——为创建一个Product对象的各个部件指定抽象接口。
    • ConcreteBuilder ——实现Builder的接口以构造和装配该产品的各个部件。

        ——定义并明确它所创建的表示。

        ——提供一个检索产品的接口。

    • Director ——构造一个使用Builder接口的对象。
    • Product ——表示被构造的复杂对象。
    • ConcreteBuilder创建该产品的内部表示并定义它的装配过程。

        ——包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

    代码示例

       ConcreteBuilder中需要提供构建产品的的各个部件的函数,以及对外获取被创建产品的接口。还是以创建迷宫为例,迷宫产品组件包括迷宫自身、房间、门,这些组件创建函数(BuildPart)需定义为虚函数,以便子类继承实现。在产品各部分创建好了后,需要通过对外的接口GetResult来获取创建的产品,本例GetMaze返回创建的迷宫。

    class MazeBuilder{
    public:
    	virtual void BuildMaze(){}
    	virtual void BuildRoom(int Room){}
    	virtual void BuildDoor(int roomFrom, int RoomTo){}
    
    	virtual Maze* GetMaze(){return 0;}
    protected:
    	MazeBuilder();
    };
    

      因为builder中BuildPart和GetResult函数都是虚函数,所以Director并不关心继承Builder的子类实现,Director只需要按部就班的调用Builder的BuildPart函数来创建产品,如下例:

    builder.BuildMaze();//创建迷宫

    builder.BuildRoom(1);//创建1号房间

    builder.BuildRoom(2);//创建2号房间

    builder.BuildDoor(1,2);//创建1号房间和2号房间的门

    在产品各个部件创建完成后,调用:

    build.GetMaze();//获取已创建迷宫

    Maze* MazeGame::CreateMaze(MazeBuilder& builder){
    	builder.BuildMaze();
    	
    	builder.BuildRoom(1);
    	builder.BuildRoom(2);
    	builder.BuildDoor(1,2);
    
    	return builder.GetMaze();
    }
    

    MazeBuilder基类提供实现产品的接口,具体实现还需要子类来实现。这里StandardMazeBuilder继承MazeBuilder并实现了基本功能。
    StandardMazeBuilder类声明:
    class StandardMazeBuilder:public MazeBuilder{
    public:
    	StandardMazeBuilder();
    
    	virtual void BuildMaze();
    	virtual void BuildRoom(int);
    	virtual void BuildDoor(int,int);
    	
    	virtual Maze* GetMaze();
    private:
    	Direction CommonWall(Room *, Room *);
    	Maze * _currentMaze;
    }
    

     StandardMazeBuilder类实现:

    #include "Builder.h"
    
    StandardMazeBuilder::StandardMazeBuilder(){
    	_currentMaze = 0;
    }
    
    void StandardMazeBuilder::BuildMaze(){
    	_currentMaze = new Maze; 
    }
    
    Maze* StandardMazeBuilder::GetMaze(){
    	return _currentMaze;
    }
    
    void StandardMazeBuilder::BuildRoom(int n){
    	if(!_currentMaze->RoomNo(n)){
    		Room* room = new Room(n);
    		_currentMaze->AddRoom(room);
    
    		room->SetSide(North, new Wall);
    		room->SetSide(South, new Wall);
    		room->SetSide(East, new Wall);
    		room->SetSide(West, new Wall);
    	}
    }
    
    void StandardMazeBuilder::BuildDoor(int n1, int n2){
    	Room *r1 = _currentMaze->RoomNo(n1);
    	Room *r2 = _currentMaze->RoomNo(n2);
    	Door *d = new Door(r1,r2);
    
    	r1->SetSide(CommonWall(r1,r2),d);
    	r2->SetSide(CommonWall(r2,r1),d);
    }
    

       在实现了Director和Builder后,Client无需关心具体产品的具体实现,只需要新建该Builder类,传递给Director,就能创建出不同的产品了。

    #include "Direcotr.h"
    #include "StandardMazeBuilder.h"
    
    int Main(){
    
    	Maze *maze;
    	MazeGame game;
    	StandardMazeBuilder builder;
    
    	game.CreateMaze(builder);
    	maze = builder.GetMaze();		
    	return 0;
    }
    

      

    优缺点

    优点:

    • 将一个复杂对象的创建过程封装起来。
    • 允许对象通过多个步骤来创建,并且可以改变过程(这和只有一个步骤的工厂模式不同)。
    • 向客户隐藏产品内部的实现。
    • 产品的实现可以被替换,因为客户只看到一个抽象的接口。

    缺点:

    • 与工厂模式相比,采用生成器创建对象的模式,需要具备更多的领域知识。

    参考文献:

    GOF《设计模式》

    《Head First设计模式》

  • 相关阅读:
    三 zookeeper集群搭建
    一 linux 基本操作
    linux x64 安装 node
    docker nginx/1.7.4
    搭建Portainer可视化界面
    Swarm搭建 Docker集群
    在 Centos7.4上安装docker
    js 处理json对象数据
    生产者消费者模式及其存在的问题
    多线程
  • 原文地址:https://www.cnblogs.com/chenyangchun/p/7326621.html
Copyright © 2020-2023  润新知