热门问题
时间线
聊天
视角

建造者模式

来自维基百科,自由的百科全书

建造者模式
Remove ads

建造者模式(英语:builder pattern),也译为生成器模式,是一种对象构建设计模式[1]。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。

Thumb
建造者结构

适用性

在以下情况使用建造者模式:

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

结构

Thumb
建造者模式的样例UML类图和序列图[2]

在上面的UML类图中,Director类不直接的创建并组装ProductA1ProductB1对象。Director转而提及Builder接口来建造(创建并组装)一个复杂对象的各部份,这使得Director独立于哪个具体类要被初始化(哪个表示要被创建)。Builder1类通过创建并组装ProductA1ProductB1对象来实现Builder接口。

UML序列图展示了运行时交互:Director对象调用buildPartA()Builder1对象之上,它创建并组装ProductA1对象。此后,Director调用buildPartB()Builder1之上,它创建并组装ProductB1对象。

参与者

  • Builder:为创建一个Product对象的各个部件指定抽象接口。
  • ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件。定义并明确它所创建的表示。提供一个检索产品的接口。
  • Director:构造一个使用Builder接口的对象。
  • Product:表示被构造的复杂对象。包含定义组成部件的类,包括将这些部件装配成最终产品的接口。ConcreateBuilder创建该产品的内部表示并定义它的装配过程。

协作

客户创建Director对象,并用它所想要的Builder对象进行配置。

  • 一旦产品部件被生成,指导者就会通知建造者。
  • 建造者处理指导者的请求,并将部件添加到该产品中。
  • 客户从建造者中检索产品。

范例

Java

Java例子:

/** "Product" */
class Pizza {
    private String dough = "";
    private String sauce = "";
    private String topping = "";
 
    public void setDough (String dough)     { this.dough = dough; }
    public void setSauce (String sauce)     { this.sauce = sauce; }
    public void setTopping (String topping) { this.topping = topping; }
}
  
/** "Abstract Builder" */
abstract class PizzaBuilder {
    protected Pizza pizza;
 
    public Pizza getPizza() { return pizza; }
    public void createNewPizzaProduct() { pizza = new Pizza(); }
 
    public abstract void buildDough();
    public abstract void buildSauce();
    public abstract void buildTopping();
}
 
/** "ConcreteBuilder" */
class HawaiianPizzaBuilder extends PizzaBuilder {
    public void buildDough()   { pizza.setDough("cross"); }
    public void buildSauce()   { pizza.setSauce("mild"); }
    public void buildTopping() { pizza.setTopping("ham+pineapple"); }
}
 
/** "ConcreteBuilder" */
class SpicyPizzaBuilder extends PizzaBuilder {
    public void buildDough()   { pizza.setDough("pan baked"); }
    public void buildSauce()   { pizza.setSauce("hot"); }
    public void buildTopping() { pizza.setTopping("pepperoni+salami"); }
}
 
 /** "Director" */
class Waiter {
    private PizzaBuilder pizzaBuilder;
 
    public void setPizzaBuilder (PizzaBuilder pb) { pizzaBuilder = pb; }
    public Pizza getPizza() { return pizzaBuilder.getPizza(); }
 
    public void constructPizza() {
        pizzaBuilder.createNewPizzaProduct();
        pizzaBuilder.buildDough();
        pizzaBuilder.buildSauce();
        pizzaBuilder.buildTopping();
    }
}
 
/** A customer ordering a pizza. */
class BuilderExample {
    public static void main(String[] args) {
        Waiter waiter = new Waiter();
        PizzaBuilder hawaiianPizzabuilder = new HawaiianPizzaBuilder();
        PizzaBuilder spicyPizzabuilder = new SpicyPizzaBuilder();
 
        waiter.setPizzaBuilder ( hawaiianPizzabuilder );
        waiter.constructPizza();
 
        Pizza pizza = waiter.getPizza();
    }
}
Remove ads

C#

C#例子:

// Represents a product created by the builder.
public class Bicycle {
    public Bicycle(string maker, string model, string colour, int height) {
        Maker = maker;
        Model = model;
        Colour = colour;
        Height = height;
    }

    public string Maker { get; set; }
    public string Model { get; set; }
    public int Height { get; set; }
    public string Colour { get; set; }
}

// The builder abstraction.
public interface IBicycleBuilder {
    Bicycle GetResult();

    string Colour { get; set; }
    int Height { get; set; }
}

// Concrete builder implementation.
public class GTBicyclesBuilder : IBicycleBuilder {
    public Bicycle GetResult() {
        return Height == 29 ? new Bicycle("GT Bicycles Inc.", "Avalanche", Colour, Height) : null;
    }

    public string Colour { get; set; }
    public int Height { get; set; }
}

// The director.
public class MountainBikeBuildDirector {
    private IBicycleBuilder _builder;

    public MountainBikeBuildDirector(IBicycleBuilder builder) {
        _builder = builder;
    }

    public void Construct() {
        _builder.Colour = "Red";
        _builder.Height = 29;
    }

    public Bicycle GetResult() {
		return this._builder.GetResult();
	}
}

public class Client {
    public void DoSomethingWithBicycles() {
        var director = new MountainBikeBuildDirector(new GTBicyclesBuilder());
        // Director controls the stepwise creation of product and returns the result.
        director.Construct();
        Bicycle myMountainBike = director.GetResult();
    }
}
Remove ads

Python

Python的例子:

from abc import ABC, abstractmethod
from weakref import WeakKeyDictionary

class Component():
    def __init__(self, name):
        self.name = name
        self.attr_dict = WeakKeyDictionary()
    def __get__(self, obj, objtype=None):
        return (self.attr_dict[obj]
            if obj in self.attr_dict else None)
    def __set__(self, obj, value):
        self.attr_dict[obj] = {'name': self.name} | value

class Product():
    part_A = Component('part_A')
    part_B = Component('part_B')
    def __init__(self, **kwargs): pass
    @property
    def description(self):
        print(f'Product: {self.part_A['name']}, {self.part_A['builder']}; '
            + f'{self.part_B['name']}, {self.part_B['builder']}.')

class Builder(ABC):
    def __init__(self, **kwargs):
        self.product = Product()
    @abstractmethod
    def build_part_A(self): pass
    @abstractmethod
    def build_part_B(self): pass
    def get_result(self):
        result, self.product = self.product, None
        return result

class BuilderA(Builder):
    params = {'builder': 'BuilderA'}
    def build_part_A(self, **kwargs): 
        self.product.part_A = type(self).params | kwargs
    def build_part_B(self, **kwargs):
        self.product.part_B = type(self).params | kwargs
        
class BuilderB(Builder):
    params = {'builder': 'BuilderB'}
    def build_part_A(self, **kwargs): 
        self.product.part_A = type(self).params | kwargs
    def build_part_B(self, **kwargs):
        self.product.part_B = type(self).params | kwargs

class Director():
    def __init__(self, builder_cls, **kwargs):
        self.builder_cls = builder_cls
    def __call__(self, **kwargs):
        self.builder = self.builder_cls()
        self.builder.build_part_A(kw='')
        self.builder.build_part_B(kw='')
        result, self.builder = self.builder.get_result(), None
        return result

其执行:

>>> product1 = Director(BuilderA)()
>>> product1.description
Product: part_A, BuilderA; part_B, BuilderA.
>>> product2 = Director(BuilderB)()
>>> product2.description
Product: part_A, BuilderB; part_B, BuilderB.
Remove ads

PHP

PHP例子:

<?php
//設計模式:生成器模式
interface Builder {
	function buildPartA(); //创建部件A比如创建汽车车轮
	//创建部件B 比如创建汽车方向盘
	function buildPartB(); 
	//创建部件C 比如创建汽车发动机
	function buildPartC(); 

	//返回最后组装成品结果 (返回最后装配好的汽车)
	//成品的组装过程不在这里进行,而是转移到下面的Director类中进行.
	//从而实现了解耦过程和部件
	//return Product
	function getResult(); 
}

class Director {
	private $builder; 

	public function __construct($builder ) { 
		$this->builder = $builder; 
	} 
	// 将部件partA partB partC最后组成复杂对象
	//这里是将车轮、方向盘和发动机组装成汽车的过程
	public function construct() {
		$this->builder->buildPartA();
		$this->builder->buildPartB();
		$this->builder->buildPartC();
	}
}

class ConcreteBuilder implements Builder {
	public $partA, $partB, $partC;
	public function buildPartA() {
		echo 'partA is builded' . "\n";
	}
	public function buildPartB() {
		echo 'partB is builded' . "\n";
	}
	public function buildPartC() {
		echo 'partC is builded' . "\n";
	}
	public function getResult () {
		echo 'Return product.' . "\n";
		return 1;
	}
}

$builder = new ConcreteBuilder();
$director = new Director( $builder ); 

$director->construct(); 
$product = $builder->getResult(); 

?>

注意问题

  • 装配和构造接口
建造者逐步的构造它们的产品。因此建造者介面必须足够普遍,以便为各种类型的具体建造者构造产品。
  • 没有抽象类
通常情况下,由具体建造者生成的产品,它们的表示相差是如此之大以至于给不同的产品以公共父类没有太大意思。
  • 在建造者中预设的方法为空
定义为空方法可以使客户只重定义他们所感兴趣的操作。

效果

  • 它使你可以改变一个产品的内部表示
  • 它将构造代码和表示代码分开
  • 它使你可对构造过程进行更精细的控制

相关模式

抽象工厂模式与建造者相似,因为它也可以创建复杂对象。主要的区别是建造者模式着重于一步步构造一个复杂对象。而抽象工厂模式着重于多个系列的产品对象(简单的或是复杂的)。建造者在最后的一步返回产品,而对于抽象工厂来说,产品是立即返回的。

合成模式通常是用建造者生成的。

引用

参考书目

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads