首页 > 其他 > 详细

设计模式-生成器模式

时间:2019-11-07 19:45:22      阅读:81      评论:0      收藏:0      [点我收藏+]

技术分享图片

前言

无论是在现实世界中还是在软件系统中,都存在一些复杂的对象,他们拥有多个组成部分,以汽车??为例,它包括车轮、方向盘、发动机等部件。对于用户而言,无须知道这些部件的装配细节,它几乎不会使用单独部件,而是使用一辆完整的汽车,可以通过生成器模式对其进行设计与描述,生成器模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部构造细节。

在软件开发中,也存在大量类似汽车一样的复杂对象,而对象的属性相当于汽车的部件,建造产品的过程就相当于组合部件的过程。由于组合部件的过程很复杂,因此,这些部件的组合过程往往被“外部化”到一个称作生成器的对象里,生成器返回给客户端的是一个已经建造完毕的完整产品对象,而用户无须关心该对象所包含的属性以及他们的组装方式,这就是生成器模式的愿景。

定义

生成器模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

生成器模式是一步一步创建一个复杂的对象,它允许用户只通过制定复杂对象的类型和内容就可以构建他们,用户不需要知道内部的具体构建细节,建造者模式属于对象创建型。

使用时机

当对象拥有好几种属性,且需要避免构造器伸缩时使用,与工厂模式运用场景不同之处在于:当创建过程仅仅一步到位,使用工厂模式,如果需要分步进行,则考虑使用生成器模式。

本质

生成器模式的本质,就是将构造函数中的参数列表方法化,长长的参数列表,无论是面向对象还是函数式编程,都是大忌,该模式主要就是为了解决该问题。

实现

C++实现

#include <iostream>

 class FriedRice {
     public:
         class FriedRiceBuilder;
         void showFlavors() {
             std::cout << _size;
             if (_egg) std::cout << "-egg";
             if (_beef) std::cout << "-beef";
             if (_onion) std::cout << "-onion";
             std::cout << std::endl;
         }
     private:
         FriedRice(int size):_size(size){}

         int _size = 0;
         bool _egg = false;
         bool _beef = false;
         bool _onion = false;
 };

 class FriedRice::FriedRiceBuilder {
     public:
         FriedRiceBuilder(int size) {_friedrice = new FriedRice(size);}
         FriedRiceBuilder& AddEgg() {_friedrice->_egg = true; return *this;}
         FriedRiceBuilder& AddBeef() {_friedrice->_beef = true; return *this;}
         FriedRiceBuilder& AddOnion() {_friedrice->_onion = true; return *this;}
         FriedRice* Build() {return _friedrice;}
     private:
         FriedRice* _friedrice;
 };

 int main() {
     FriedRice* friedRice = FriedRice::FriedRiceBuilder(7).AddEgg().AddBeef().AddOnion().Build();
     friedRice->showFlavors();
     return 0;
 }

golang实现

package builder

type Builder interface {
    part1()
    part2()
    part3()
}

type Director struct {
    builder Builder
}

func NewDirector(b Builder) *Director {
    return &Director{builder: b}
}

func (d *Director) Constructor() {
    d.builder.part1()
    d.builder.part2()
    d.builder.part3()
}

type FirstBuilder struct {
    result string
}

func (fb *FirstBuilder) part1() {
    fb.result += "1"
}

func (fb *FirstBuilder) part2() {
    fb.result += "2"
}

func (fb *FirstBuilder) part3() {
    fb.result += "3"
}

func (fb *FirstBuilder) Result() string {
    return fb.result
}

type SecondBuilder struct {
    result string
}

func (sb *SecondBuilder) part1() {
    sb.result += "11"
}

func (sb *SecondBuilder) part2() {
    sb.result += "22"
}

func (sb *SecondBuilder) part3() {
    sb.result += "33"
}

func (sb *SecondBuilder) Result() string {
    return sb.result
}

测试用例

package builder

import (
    "reflect"
    "testing"
)

func TestFirstBuilder_Result(t *testing.T) {
    fb := FirstBuilder{}
    d := NewDirector(&fb)
    d.Constructor()
    if reflect.ValueOf(d.builder).Interface().(*FirstBuilder).Result() != "123" {
        t.Error("first builder test failed")
    }
}

func TestSecondBuilder_Result(t *testing.T) {
    sb := SecondBuilder{}
    d := NewDirector(&sb)
    d.Constructor()
    if reflect.ValueOf(d.builder).Interface().(*SecondBuilder).Result() != "112233" {
        t.Error("second builder test failed")
    }
}

测试结果

go test -v .
=== RUN   TestFirstBuilder_Result
--- PASS: TestFirstBuilder_Result (0.00s)
=== RUN   TestSecondBuilder_Result
--- PASS: TestSecondBuilder_Result (0.00s)
PASS
ok      design-patterns/builder 0.521s

优缺点

优点

  • 松散耦合
    生成器模式可以用同一个构建算法构建出表现上完全不同的产品,实现产品构建和产品表现上的分离。生成器模式正是把产品构建的过程独立出来,使它和具体产品的表现松散耦合,从而使得构建算法可以复用,而具体产品表现也可以灵活地、方便地扩展和切换。
  • 可以很容易地改变产品的内部表示
    在生成器模式中,由于FriedRiceBuilder对象只是提供接口给FriedRice使用,那么具体的部件创建和装配方式是被FriedRiceBuilder接口隐藏了的,FriedRice并不知道这些具体的实现细节。这样一来,要想改变产品的内部表示,只需要切换FriedRiceBuilder的具体实现即可,不用管FriedRice,因此变得很容易。
  • 更好的复用性
    生成器模式很好地实现了构建算法和具体产品实现的分离。这样一来,使得构建产品的算法可以复用。同样的道理,具体产品的实现也可以复用,同一个产品的实现,可以配合不同的构建算法使用。

缺点

  • 生成器模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用生成器模式,因此其使用范围受到一定的限制。
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体生成器类来实现这种变化,导致系统变得很庞大。

设计模式-生成器模式

原文:https://www.cnblogs.com/jingliming/p/11814231.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!