工厂模式(headfirst)笔记

工厂模式(主要是自己的笔记:水平较低,请勿语言攻击)

除了new操作符之外还有很多制造对象的方法,用new初始化对象经常会造成耦合的问题,这时候就会用到工厂模式。

每次使用new时,都是在针对具体的实现有点违背设计原则(针对接口编程,而不是针对实现编程),如果遇到会改变的东西,应该尽量想到针对接口编程,可以隔离掉以后可能会发生的变化。

以下是headfirst中的例子(披萨店)

一般我们创建一个pizza会直接Pizza pizza = new Pizza();

因为后面披萨店的披萨有很多种,所以我们希望pizza是一个接口,所有类型的pizza都要继承这个接口

可以这样写

public Pizza OrderPizza(string type)
{
Pizaa pizza;
if(type.equals("cheese"))
{
pizza
=new CheesePizza();
}
elseif(type.equals("greek"))
{
pizza
=new GreekPizza();
}
       pizza.Prepare();
       pizza.Bake();
       ...
       return pizza;
}

  但是压力来自于增加和减少更多的pizza类型,后来你可能想增加几个新类型pizza,或者把不好吃的披萨干掉,你还要打开这段代码修改,这部分是变化的所以应该尽可能的封装起来。把这部分变化的剪切到一个新类里面,如果增加新对象就在这里增加就可以了,这个新类就是我们要学的工厂,当需要pizza时直接让这个工厂去new一个符合条件的就可以了,然后下面就是改进后的简单工厂的代码

public class PizzaStore
{
public Pizza OrderPizza(string type)
{
Pizza pizza;
pizza
= SimplePizzaFactory.CreatePizza(type);
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}

}
publicclass SimplePizzaFactory
{
publicstatic Pizza createPizza(string type)
{
Pizza pizza
=null;
if (type.Equals("cheese"))
pizza
=new CheesePizza();
elseif (type.Equals("pepperoni"))
pizza
=new PepperoniPizza();
return pizza;
}
}

 这是简单工厂,简单工厂不是一个设计模式,而更像是一种编程习惯,由于经常使用所以经常被误认为工厂模式。

 以上是简单工厂,下面是真正的工厂模式,还是用上个例子,只不过现在披萨店要开分店了,上面代码应该改为PizzaStore是一个超类,下面有好几个披萨店继承自它,每个披萨可以决定自己的风格。以下    是代码

publicabstractclass PizzaStore
{
public Pizza OrderPizza(string type)
{
Pizza pizza;
pizza
= CreatePizza(type);
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}

publicabstract Pizza CreatePizza(string type);
}

publicclass NYPizzaStore : PizzaStore
{
publicoverride Pizza CreatePizza(string item)
{
if (item.Equals("cheese"))
{
returnnew NYStyleCheesePizza();
}
else
returnnull;
}
}

publicclass ChicagoPizzaStore : PizzaStore
{
publicoverride Pizza CreatePizza(string item)
{
if (item.Equals("cheese"))
{
returnnew ChicagoStyleCheesePizza();
}
else
returnnull;
}
}

publicabstractclass Pizza
{
publicstring Name { get; set; }
publicstring Dough { get; set; }
publicstring Sauce { get; set; }
public ArrayList toppings =new ArrayList();

publicvoid Prepare()
{
Console.WriteLine(
"Preparing "+ Name);
Console.WriteLine(
"Tossing dough...");
Console.WriteLine(
"Adding sauce...");
Console.WriteLine(
"Adding toppings:");
for (int i =0; i < toppings.Count; i++)
{
Console.WriteLine(
""+ toppings[i]);
}
}

publicvirtualvoid Bake()
{
Console.WriteLine(
"Bake for 25 minutes at 350");
}

publicvirtualvoid Cut()
{
Console.WriteLine(
"Cutting the pizza into diagonal slices");
}

publicvirtualvoid Box()
{
Console.WriteLine(
"Place pizza in official PizzaStore box");
}

publicstring GetName()
{
return Name;
}
}

publicclass NYStyleCheesePizza : Pizza
{
public NYStyleCheesePizza()
{
Name
="Ny Style Deep Dish Cheese Pizza";
Dough
="Extra Thin Crust Dough";
Sauce
="Marinara Sauce";

toppings.Add(
"Grated Reggiano Cheese");
}
}

publicclass ChicagoStyleCheesePizza : Pizza
{
public ChicagoStyleCheesePizza()
{
Name
="Chicago Style Deep Dish Cheese Pizza";
Dough
="Extra Thick Crust Dough";
Sauce
="Plum Tomato Sauce";

toppings.Add(
"Shredded Marinara Cheese");
}

publicoverridevoid Cut()
{
Console.WriteLine(
"Cutting the pizza into square slice");
}
}

staticvoid Main(string[] args)
{
PizzaStore nyStore
=new NYPizzaStore();
PizzaStore chicagoStore
=new ChicagoPizzaStore();

Pizza pizza
= nyStore.OrderPizza("cheese");
Console.WriteLine(
"Ethan Ordered a "+ pizza.GetName() +"\n");
pizza
= chicagoStore.OrderPizza("cheese");
Console.WriteLine(
"Joel order a "+ pizza.GetName() +"\n");
}

  所有的工厂模式都是用来封装对象的创建,工厂方法模式通过让子类决定创建的对象是上面,来达到降对象创建的过程封装的目的。以上主要是有创建者类和产品类组成

  创建者类是抽象类,定义了一个抽象工厂方法,让子类实现此方法制造产品,通常会包含依赖抽象产品的代码能够产生产品的类称为具体创造者(NYPizzaStore,ChicagoPizzaStore).

    工厂方法模式定义了一个创建对象的接口,但由于子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。

  依赖倒置原则:要依赖抽象,不要依赖具体类

  在本例中能很好的体现出来这个原则,披萨店不要依赖于具体实现披萨的类,依赖于披萨类,那倒置又是什么意思呢,具体的披萨类依赖于抽象类而披萨店类也依赖于抽象的的披萨,而不相互依赖。

  例如你需要实现一个披萨店,你第一件想到的事情是什么?就是从顶端进行准备,烘烤,装盒。。。制作不同口味的披萨,应该倒置你的想法,不要从顶端开始,而是从pizza开始,先抽象化一个pizza,现在回头重新考虑如何设计店,必须靠一个工厂来将这些具体类取出比萨店,各种不同的披萨店会依赖这个抽象。

几个指导方针,能帮你避免OO设计中违反依赖倒置原则

1.变量不可以持有具体类的引用

2.不要让类派生自具体类

3.不要覆盖基类中实现的方法

posted @ 2011-07-29 13:58  CircleLee  阅读(260)  评论(0)    收藏  举报