您的位置:首页 > 其它

《Head First Design Patterns》笔记四:工厂模式(Factory Pattern)

2009-04-27 15:17 555 查看
引言

工厂模式,字面就很好的解释了这个模式,我们日常生活用的电器,穿的衣服,玩的电脑,是怎么作出来的,大多数人都跟我一样,稀里糊涂搞不大懂,也不需要去了解,比方说衣服生产的厂家换了制作工艺,我们需要去了解吗.不需要,只需要的就是花钱去购买,就是说事物不管怎么变,处理事物的方式不变.

ok,这就是工厂模式,多么优美的方式,引申到软件里面,就是不管某项事物如何变化,我处理这个事务都不需要改变.

需求

我们来看个例子,一家披萨店开张. 的我们需要一个订单系统,pizza店披萨包括3种 素食的, 蛤蜊风味的, 奶酪馅饼的. 简单分析下,创建IPizza接口,和3种风味的pizza类ClamPizza, VeggiePizza 和CheesePizza .下面列出订单Order的代码:

public IPizza OrderPizza(string type)
{
IPizza pizza=null;
switch(type)
{
"Veggie":pizza=new VeggiePizza();break;
"Cheese":pizza=new CheesePizza();break;
"Clam":pizza=new ClamPizza();break;
}
pizza.Prepare();
pizza.Bake();
pizza.Cut();
return pizza;
}


这看来已经不错,但考虑如果有了新品种的pizza加入呢,我们必须修改这个类的代码,这违反了什么原则,对,就是设计原则的"把变化的事物分离出来",这里变化的是创建pizza的那一段代码,所以我们考虑,加1个Factory类,专门负责CreatePizza把它分离出来:代码如下:

public class Order
{
public IPizza OrderPizza(string type)
{
IPizza pizza=Factory.CreatePizza(type);
pizza.Prepare();
pizza.Bake();
pizza.Cut();
return pizza;
}
}

public class Factory
{
public static IPizza CreatePizza(string type)
{
IPizza pizza=null;
switch(type)
{
"Veggie":pizza=new VeggiePizza();break;
"Cheese":pizza=new CheesePizza();break;
"Clam":pizza=new ClamPizza();break;
}
retun pizza;
}
}


ok,很不错了,变化的代码我们已经分离出来了,我们有了新的品种,只需要更改Factory,对于实际应用代码不需要做任何改动.

思考:这看上去好像没什么用,只是把代码移出来而已,有什么用啊? 这段代码看上去确实如此,但是我们需要知道,Create和order这2个类现在呈现松耦合,相互不影响.而且Create方法还可能会有其他的类里调用,就是说这样做导致代码灵活性,和可维护性提高.

这样的代码我们实际应用中使用十分多,所以我们说工厂模式可以说无处不在.

不过,这并不是真正的工厂模式,而是称之为简单工厂模式,就是说只有1个工厂,实现制造产品的方法往往会使用statc修饰.

分析

完全的工厂模式是怎样的呢,我们考虑下披萨店如果现在在不同的城市开连锁店,这里以美国城市为例,new york和chicago,那么怎么去处理呢,这就是应用工厂模式的好时候了,工厂模式uml图先如下



就是在定义一个制造事物的接口,但是只在子类实现它.

了解这点,我们可以动手披萨店的改造了,先画uml视图:



看uml图,依赖关系为Ipizza和pizzaSotre这2个抽象(接口)类,这样符合设计原则:依赖于抽象,而不是实际类.

实现


最后还是代码实现了,首先是Pizza,包括6个pizza实现类和1个Pizza接口.

//file 1:IPizza.cs
using System;
public interface IPizza
{
string Name{get;}
void Prepare();
void Bake();
void Cut();
}
//file 2:ChicagoCheesePizza.cs
using System;
public class ChicagoCheesePizza:IPizza
{
public string Name
{
get{return "Chicago style Cheese Pizza";}
}
public void Prepare()
{
Console.WriteLine("this is "+Name);
Console.WriteLine("Prepared the Ingredients");
}
public void Bake()
{
Console.WriteLine("Bake for 20 minutes");
}
public void Cut()
{
Console.WriteLine("Cut into 4 piece");
}
}
//file 3:ChicagoClamPizza.cs
using System;
public class ChicagoClamPizza:IPizza
{
public string Name
{
get{return "Chicago style Clam Pizza";}
}
public void Prepare()
{
Console.WriteLine("this is "+Name);
Console.WriteLine("Prepared the Ingredients");
}
public void Bake()
{
Console.WriteLine("Bake for 25 minutes");
}
public void Cut()
{
Console.WriteLine("Cut into slices");
}
}
//file 4:ChicagoVeggiePizza.cs
using System;
public class ChicagoVeggiePizza:IPizza
{
public string Name
{
get{return "Chicago style Veggie Pizza";}
}
public void Prepare()
{
Console.WriteLine("this is "+Name);
Console.WriteLine("Prepared the Ingredients");
}
public void Bake()
{
Console.WriteLine("Bake for 21 minutes");
}
public void Cut()
{
Console.WriteLine("Cut into 3 piece");
}
}
//file 5:NYCheesePizza.cs
using System;
public class NYCheesePizza:IPizza
{
public string Name
{
get{return "New York style Cheese Pizza";}
}
public void Prepare()
{
Console.WriteLine("this is "+Name);
Console.WriteLine("Prepared the Ingredients");
}
public void Bake()
{
Console.WriteLine("Bake for 20 minutes");
}
public void Cut()
{
Console.WriteLine("Cut into 3 piece");
}
}
//file 6:NYClamPizza.cs
using System;
public class NYClamPizza:IPizza
{
public string Name
{
get{return "New York style Clam Pizza";}
}
public void Prepare()
{
Console.WriteLine("this is "+Name);
Console.WriteLine("Prepared the Ingredients");
}
public void Bake()
{
Console.WriteLine("Bake for 24 minutes");
}
public void Cut()
{
Console.WriteLine("Cut into slices");
}
}
//file 7:NYVeggiePizza.cs
using System;
public class NYVeggiePizza:IPizza
{
public string Name
{
get{return "New York style Veggie Pizza";}
}
public void Prepare()
{
Console.WriteLine("this is "+Name);
Console.WriteLine("Prepared the Ingredients");
}
public void Bake()
{
Console.WriteLine("Bake for 23 minutes");
}
public void Cut()
{
Console.WriteLine("Cut into 3 piece");
}
}


然后是PizzaStore了,包括abstract类PizzaStore.cs和NYPizzaStore,ChicagoPizzaStore实现类,和一个enum PizzaType

//file 1:enum
public enum PizzaType
{
Veggie,Cheese,Clam
}
//file 2:PizzaStore.cs
using System;
public abstract class PizzaStore
{
public IPizza OrderPizza(PizzaType type)
{
IPizza pizza=CreatePizza(type);
pizza.Prepare();
pizza.Bake();
pizza.Cut();
return pizza;
}
public abstract IPizza CreatePizza(PizzaType type);
}
//file 3:ChicagoPizzaStore.cs
using System;
public class ChicagoPizzaStore:PizzaStore
{
public override IPizza CreatePizza(PizzaType type)
{
IPizza pizza=null;
switch(type)
{
case PizzaType.Cheese:pizza=new ChicagoCheesePizza();break;
case PizzaType.Clam:pizza=new ChicagoClamPizza();break;
case PizzaType.Veggie:pizza=new ChicagoVeggiePizza();break;
}
return pizza;
}
}
//file 4:NYPizzaStore.cs
using System;
public class NYPizzaStore:PizzaStore
{
public override IPizza CreatePizza(PizzaType type)
{
IPizza pizza=null;
switch(type)
{
case PizzaType.Cheese:pizza=new NYCheesePizza();break;
case PizzaType.Clam:pizza=new NYClamPizza();break;
case PizzaType.Veggie:pizza=new NYVeggiePizza();break;
}
return pizza;
}
}


最后客户端实现了,代码如下:

//file :Program.cs
using System;
public class Program
{
public static void Main()
{
PizzaStore store=new ChicagoPizzaStore();
store.OrderPizza(PizzaType.Veggie);
store.OrderPizza(PizzaType.Cheese);
store=new NYPizzaStore();
store.OrderPizza(PizzaType.Clam);
store.OrderPizza(PizzaType.Cheese);
}
}


结果如下:

this is Chicago style Veggie Pizza
Prepared the Ingredients
Bake for 21 minutes
Cut into 3 piece
this is Chicago style Cheese Pizza
Prepared the Ingredients
Bake for 20 minutes
Cut into 4 piece
this is New York style Clam Pizza
Prepared the Ingredients
Bake for 24 minutes
Cut into slices
this is New York style Cheese Pizza
Prepared the Ingredients
Bake for 20 minutes
Cut into 3 piece

增强

上面例子是工厂模式的很好应用,但是我们现在在考虑连锁店越开越多,连锁店都是本地化,有些连锁店为了多赚钱,用的材料不大好,这可是损害品牌形象的大灾星.那我们该怎么控制材料呢,馅饼的材料一般都不会有多少变化,有生面团,酱料,奶酪,素菜等等,这里不一一列出.我们考虑抽象工厂模式,uml如下:



这里跟工厂模式不一样的是抽象类里包括不止一个产品需要实现,当产品类别不会有大的更改的时候就可以使用抽象工厂.Ingredients类看uml图就可以很理解,代码这里不列出来了.旧的代码升级,这里仅列出NYPizzaStore.cs和NYCheesePizza.cs这2段代码,其他代码也类似的修改,不一一列出了.当然,客户端实现没有影响,不需要修改.代码如下:

//file 1 :store
using System;
public class NYPizzaStore:PizzaStore
{
IIngredientsFactory _ingredients;
public NYPizzaStore()
{
this._ingredients=new NYIngredientsFactory();
}
public override IPizza CreatePizza(PizzaType type)
{
IPizza pizza=null;
switch(type)
{
case PizzaType.Cheese:pizza=new NYCheesePizza(ingredients);break;
case PizzaType.Clam:pizza=new NYClamPizza(ingredients);break;
case PizzaType.Veggie:pizza=new NYVeggiePizza(ingredients);break;
}
return pizza;
}
}
//file 2:pizza
using System;
public class NYCheesePizza:IPizza
{
IIngredientsFactory _ingredients;
private IDouce douce;
private ISauce sauce;
private IClam clam;
private ICheese cheese;
private IVeggie veggie;
public string Name
{
get{return "New York style Cheese Pizza";}
}
public void Prepare()
{
Console.WriteLine("this is "+Name);
douce=_ingredients.CreteDouce();
sauce=_ingredients.CreateSauce();
cheese=_ingredients.CreateCheese();
}
public void Bake()
{
Console.WriteLine("Bake for 20 minutes");
}
public void Cut()
{
Console.WriteLine("Cut into 3 piece");
}
}


下一篇:《Head First Design Patterns》笔记五:单件模式(Singleton Pattern)

上一篇:《Head First Design Patterns》笔记三:装饰者模式(Decorator Pattern)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: