Design Pattern - Creational Patterns - Builder Pattern

50 篇文章 0 订阅
37 篇文章 0 订阅

2007

Section 3, Chapter 2


Builder Pattern


Concept

Builders usually deal with construction of complex objects or objects whose construction, initialization, and configuration spans more than one process and whose creational code is complex.


Use

Builders are used to prevent duplication of creational code, and act as a central repository for the creational code involved. So a builder might be used when you have several processes that aid in the creation of an object, and the object's creation or initialization is dependent on each of these processes.


Builders are useful for any creational methods spanning a number of operations. They are also useful for maintaining the order of the operations in creating classes. Using inheritance, we can make sure builders can provide us polymorphic processing of creational logic and can change this logic across inherited implementations. Using builders we can create a class, initialize its state, and maintain the order of operations for how the class gets created and configured. We can use builders in a variety of ways with factories and provide either added functionality or enhanced usability in their association.


Design

  • Builder: responsible for defining and producing individual parts of a whole class or product. It holds a number of processes needed to build, initialize, and configure the product class.
  • Director: the class that helps the builder to put all the methods together in a cohesive and consequential manner.
  • Product: the class that is produced from the builder-director relationship.




Illustration



We need a way to make sure we perform the same order of operations for any builder. For this purpose we create a Director class that has a method that receives as an input parameter the abstract HouseBuilder class. Inside the director class's Construct() method we identify each operation and its order of execution. This ensures that no matter which House class we want to create we always configure them in a uniform manner.


public abstract class HouseBuilder
{
  public abstract House CreateHouse();
  public abstract Floor CreateFloor();
  public abstract Wall CreateWall();
  public abstract Roof CreateRoof();
}

class DuplexBuilder : HouseBuilder
{
  public override House CreateHouse()
  {
    return new Duplex();
  }
  public override Floor CreateFloor()
  {
    return new CementFloor();
  }
  public override Wall CreateWall()
  {
    return new CementBlockWall();
  }
  public override Roof CreateRoof()
  {
    return new ShingledRoof();
  }
}

class HouseDirector
{
  public House Construct(HouseBuilder builder)
  {
    House house = builder.CreateHouse();
    house.Floor = builder.CreateFloor();
    house.EastWall = builder.CreateWall();
    house.WestWall = builder.CreateWall();
    house.SouthWall = builder.CreateWall();
    house.NorthWall = builder.CreateWall();
    house.Roof = builder.CreateRoof();
    return house;
  }
}

HouseDirector director = new HouseDirector();
House duplex = director.Construct(new DuplexBuilder());
House hud = director.Construct(new HUDBuilder());


With Factory pattern:


public abstract class Suit
{
  Tie _tie;
  Belt _belt;
  public Tie Tie
  {
    get{return _tie;}
    set{_tie = value;}
  }
  public Belt Belt
  {
    get{return _belt;}
    set{_belt = value;}
  }
}

public class Armani : Suit
{
  CuffLinks _cuffLinks;
  public CuffLinks CuffLinks
  {
    get{return _cuffLinks;}
    set{_cuffLinks = value;}
  }
}

public class StripedBusinessSuit : Suit {}

public class PlaidBusinessSuit : Suit {}

public class GolfSuit : Suit {}


public abstract class Builder
{
  public abstract void CreateEnsemble(ref Suit suit);
}

public class GolfSuitBuilder : Builder
{
  public override void CreateEnsemble(ref Suit suit)
  {
    GolfSuit aSuit = (GolfSuit)suit;
    aSuit.Tie = null;
    aSuit.Belt = new LeatherBelt();
  }
}

public class ArmaniBuilder : Builder
{
  public override void CreateEnsemble(ref Suit suit)
  {
    Armani aSuit = (Armani)suit;
    aSuit.Tie = new StripedTie();
    aSuit.Belt = new LeatherBelt();
    aSuit.CuffLinks = new GoldCuffLinks();
    //extended attribute for Armani
  }
}


public sealed class SuitFactory
{
  ...
  public void Register(SuitType suitType, Type type, Builder builder)
  {
    _registered.Add(suitType, type);
    _builders.Add(suitType, builder);
  }
  public Suit CreateSuit(SuitType suitType)
  {
    if(_loaded[suitType] == null)
      Load();
    Suit suit = (Suit)_loaded[suitType];
    
    // overwrite the suit object if it has its specific builder
    if(_builders[suitType] != null)
    {
      Builder builder = (Builder)_builders[suitType];
      builder.CreateEnsemble(ref suit);
    }
    
    return suit;
  }
}


SuitFactory factory = new SuitFactory();
factory.Register(SuitType.Armani, typeof(Armani), new ArmaniBuilder());
factory.Register(SuitType.GolfSuit, typeof(GolfSuit), new GolfSuitBuilder());
factory.Register(SuitType.PlaidBusinessSuit, typeof(PlaidBusinessSuit), null);
factory.Register(SuitType.StripedBusinessSuit, typeof(StripedBusinessSuit), null);


Suit suit = factory.CreateSuit(SuitType.Armani);
suit = factory.CreateSuit(SuitType.GolfSuit);
suit = factory.CreateSuit(SuitType.PlaidBusinessSuit);
suit = factory.CreateSuit(SuitType.StripedBusinessSuit);


Note: The implementation of load() in factory class is unclear.



December 2007

Section 2, Chapter 6



Design



  • IBuilder: An interface defining what can be built
  • Director: A sequence of operations that can be followed to create a Product
  • Builder: A class that is called by a Director to make Product parts
  • Product: The object under construction, by parts


The Builder pattern is based on Directors and Builders.

Any number of Builder classes can conform to an IBuilder interface, and they can be called by a director to produce a product according to specification.

Different builders can supply different parts.

There can be several Directors and Builders.

The client calls Construct for a particular Director with a particular Builder. The Director has an individual way of putting together parts on offer from the Builder interface. The Product maintains a running list of the parts as they are created, and this list is the result of the construction process.



Implementation


using System;
using System.Collections.Generic;

// Builder Pattern Judith Bishop November 2007
// Simple theory code with one director and two builders
class Director {
	// Build a Product from several parts
	public void Construct(IBuilder builder) {
		builder.BuildPartA();
		builder.BuildPartB();
		builder.BuildPartB();
	}
}

interface IBuilder {
	void BuildPartA();
	void BuildPartB();
	Product GetResult();
}

class Builder1: IBuilder {
	private Product product = new Product();
	public void BuildPartA() {
		product.Add("PartA ");
	}
	public void BuildPartB() {
		product.Add("PartB ");
	}
	public Product GetResult() {
		return product;
	}
}

class Builder2: IBuilder {
	private Product product = new Product();
	public void BuildPartA() {
		product.Add("PartX ");
	}
	public void BuildPartB() {
		product.Add("PartY ");
	}
	public Product GetResult() {
		return product;
	}
}

class Product {
	List < string > parts = new List < string > ();
	public void Add(string part) {
		parts.Add(part);
	}
	public void Display() {
		Console.WriteLine("\nProduct Parts -------");
		foreach(string part in parts)
		Console.Write(part);
		Console.WriteLine();
	}
}

public class Client {
	public static void Main() {
		// Create one director and two builders
		Director director = new Director();
		IBuilder b1 = new Builder1();
		IBuilder b2 = new Builder2();
		// Construct two products
		director.Construct(b1);
		Product p1 = b1.GetResult();
		p1.Display();
		director.Construct(b2);
		Product p2 = b2.GetResult();
		p2.Display();
	}
}



using System;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace BuilderPattern {
	// Builder Pattern D-J Miller and Judith Bishop Sept 2007
	// Abstract Factory : Builder Implementation
	interface IBuilder<Brand> where Brand: IBrand {
		IBag CreateBag();
	}

	// Abstract Factory now the Builder
	class Builder<Brand> :IBuilder<Brand> where Brand: IBrand,
	new() {
		Brand myBrand;
		public Builder() {
			myBrand = new Brand();
		}
		public IBag CreateBag() {
			return myBrand.CreateBag();
		}
	}

	// Product 1
	interface IBag {
		string Properties {
			get;
			set;
		}
	}

	// Concrete Product 1
	class Bag: IBag {
		public string Properties {
			get;
			set;
		}
	}

	// Directors
	interface IBrand {
		IBag CreateBag();
	}

	class Gucci: IBrand {
		public IBag CreateBag() {
			Bag b = new Bag();
			Program.DoWork("Cut Leather", 250);
			Program.DoWork("Sew leather", 1000);
			b.Properties += "Leather";
			Program.DoWork("Create Lining", 500);
			Program.DoWork("Attach Lining", 1000);
			b.Properties += " lined";
			Program.DoWork("Add Label", 250);
			b.Properties += " with label";
			return b;
		}
	}

	class Poochy: IBrand {
		public IBag CreateBag() {
			Bag b = new Bag();
			Program.DoWork("Hire cheap labour", 200);
			Program.DoWork("Cut Plastic", 125);
			Program.DoWork("Sew Plastic", 500);
			b.Properties += "Plastic";
			Program.DoWork("Add Label", 100);
			b.Properties += " with label";
			return b;
		}
	}

	class Client <Brand> where Brand: IBrand,
	new() {
		public void ClientMain() //IFactory<Brand> factory) {
		IBuilder<Brand> factory = new Builder<Brand>();
		DateTime date = DateTime.Now;
		Console.WriteLine("I want to buy a bag!");
		IBag bag = factory.CreateBag();
		Console.WriteLine("I got my Bag which took " + DateTime.Now.Subtract(date).TotalSeconds * 5 + " days");
		Console.WriteLine(" with the following properties " + bag.Properties + "\n");
	}
}

static class Program {
	static void Main() {
		// Call Client twice
		new Client<Poochy>().ClientMain();
		new Client<Gucci>().ClientMain();
	}
	public static void DoWork(string workitem, int time) {
		Console.Write("" + workitem + ": 0%");
		Thread.Sleep(time);
		Console.Write("....25%");
		Thread.Sleep(time);
		Console.Write("....50%");
		Thread.Sleep(time);
		Console.WriteLine("....100%");
	}
}


where

new() {...}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值