创建者模式学习心得
适用场景:
某个东西需要由其他的东西组合而成。
如中国移动的套餐,套餐A是由短信包1和长话包2组成的;套餐B是由短信包2和长话包3组成的。
适合应付这样的变化:如果套餐的数目不确定,并且里面的包的数目和类别也不确定。
比如中国移动的套餐随着时间的变化,需要不断变化,并且不断推出新的套餐品种。
本文的例子场景:
搭配衣服场景。
一个人要去找工作,首先要选择一个合适的套装(Suit)。
而套装又是由上衣(Jacket)、裤子(pants)和鞋子(Shoe)组成的。
他要根据不同的工作性质选择不同的衣服。
涉及对象:
1。需要穿衣服的人:Client
2。指导它穿哪套套装的对象:Director
3。A套装的构造者:ABuilder,B套装的构造者:BBuilder,C套装的构造者:CBuilder
和他们继承的接口:IBuilder
4。套装:Suit
5。上衣:Jacket、裤子:pants、鞋子:shoe
类的关系图:图1
具体实现方法:
1。Client的职责是选择一种套装。client需要输入他所选择的套装类型。
class Client
{
staticvoidMain(string[]args)
{
//testBuilderPattern
Directordirector=newDirector();
IBuilderbuilder;
Console.WriteLine("inputyourchoice:A,BorC?");
stringSignal=Console.ReadLine();
builder=director.ConstructSuit(Signal);
Suitsuit=builder.GetSuit();
suit.Show();
Console.ReadLine();
}
}
2。Director的职责是找出可以创建该套装的“创建者”。
他是沟通Client的需求和“创建者”工作的一个中间环节。
public class Director
{
publicIBuilderConstructSuit(stringSignal)
{
switch(Signal)
{
case"A":{returnnewABuilder();}
case"B":{returnnewBBuilder();}
case"C":{returnnewCBuilder();}
default:returnnull;
}
}
}
3。ABuilder、BBuilder、CBuilder均实现IBuilder的接口,
用来创建A种的Suit、B种Suit、C种Suit。
public interface IBuilder
{
SuitGetSuit();
}
public class ABuilder:IBuilder
{
publicSuitGetSuit()
{
JacketjacketA=newJacket("A");
PantspantsA=newPants("A");
ShoeshoeA=newShoe("A");
SuitsuitA=newSuit(jacketA,pantsA,shoeA);
returnsuitA;
}
}
public class BBuilder:IBuilder
{
publicSuitGetSuit()
{
JacketjacketB=newJacket("B");
PantspantsB=newPants("B");
ShoeshoeB=newShoe("B");
SuitsuitB=newSuit(jacketB,pantsB,shoeB);
returnsuitB;
}
}
public class CBuilder:IBuilder
{
publicSuitGetSuit()
{
JacketjacketC=newJacket("C");
PantspantsC=newPants("C");
ShoeshoeC=newShoe("C");
SuitsuitC=newSuit(jacketC,pantsC,shoeC);
returnsuitC;
}
}
4。套装类。他的职责是规范一个套装应该有的三个部分,并且根据这三个部分创建出套装
public class Suit
{
JackettheJacket;
PantsthePants;
ShoetheShoe;
publicSuit(Jacketjacket,Pantspants,Shoeshoe)
{
theJacket=jacket;
thePants=pants;
theShoe=shoe;
}
publicvoidShow()
{
theJacket.show();
thePants.Show();
theShoe.Show();
}
}
5。裤子、衣服和鞋子,均是最基本的构成,职责是通过传入的 参数构造出一个自己:
public class Jacket
{
publicstringJacketType;
publicJacket(stringjacketType)
{
JacketType=jacketType;
}
publicvoidshow()
{
Console.WriteLine("I'm"+JacketType+"jacket");
}
}
public class Pants
{
publicstringPantsColor;
publicPants(stringpantsColor)
{
PantsColor=pantsColor;
}
publicvoidShow()
{
Console.WriteLine("I'm"+PantsColor+"colorPants");
}
}
public class Shoe
{
publicstringShoeSize;
publicShoe(stringshoeSize)
{
ShoeSize=shoeSize;
}
publicvoidShow()
{
Console.WriteLine("I'mShoeof"+ShoeSize);
}
}
效果:
按照传统的思维,我们会这样处理这个问题:
创建一个Suit的父类,然后不断的继承它,从而创造出A、B、C三种套装。
client根据自己的需求,来选择实例化不同的套装。
但是这样有什么缺点呢?
1。使用创建者模式的时候,Client并不必知道Suit这个东西,它只面对Director,
它只需要知道到底是A、B还是C。他不用关心到底是Suit还是Coad,或者是其他什么东西。
如果说在构造套餐之外,有其他的需求是和A、B、C的选择相关的,就可以体现出创建者模式的优势。
比如,A表示“严肃”系列,适合应聘行政工作;B表示“休闲”系列,适合应聘美工。
Client在对Director作出A、B的选择后,除了获得了一个合适的Suit,还需要获得一份“面试指导”。
这时候Director就可以调用其他对象了
2。builder之间更加松耦合。相对于传统的方法,它和Suit的关系是“使用”,而不是“继承”。
3。构造的过程可以更加精细控制。比如说,某种Suit不需要shoe了,它只要有jacket和pants就可以了。
它可以先构造jacket,也可以先构造shoe。。。
4。构建代码和表现代码分离。构造是在Builder类里面实现的,而表现是由suit实现的。
这样实现了控制和表现的分离。
5。不同的suit只是不同jacket、pants和shoe的排列组合而已,从概念上说不是继承的关系。
补充说明:
和工厂模式的区别:
1。builer的重点是在不同的请求下,给出不同的排列组合。
Factory的重点是在不同的请求下,给出不同类的实例。
2。Builder不需要一个抽象的Suit。而用工厂就需要了。
附:用工厂实现这个需求的类图:图2
这样的场景比较适合使用工厂:一个人要选择面试的裤子:它如果选A就给Apants,选B就给Bpants。。。
代码的优化:
其中,Director可以采用映射生成一个实例
这样的话,Director中就不需要出现A、B的字眼了。
public class Director
{
publicIBuilderConstructSuit(stringSignal)
{
//switch(Signal)
//{
//case"A":{returnnewABuilder();}
//case"B":{returnnewBBuilder();}
//case"C":{returnnewCBuilder();}
//default:returnnull;
//}
return(IBuilder)Assembly.Load("ConsoleApplication1").CreateInstance("BuilderPattern."+Signal+"Builder");
}
}
模式应用:
这个模式的应用范围非常广。这种类似于“套餐”的 都可以应用。
1。用户页面的定制。
2。自动生成网站系统中的页面布局。如果可以做成这样的话,那网站只需要一个页面 了
根据它的需求定制它的控件就可以了。
3。DataList的建造
4。用户订阅不同的信息,其实也是套餐。