工厂模式(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.不要覆盖基类中实现的方法
浙公网安备 33010602011771号