工厂模式
定义一个创建对象的接口,由子类决定要实例化的类。工厂方法将类实例推迟到子类。依赖倒置。
第一种方式是:
class PizzaStore
{
PizzaFactory pizzaFactory;
public PizzaStore(PizzaFactory factory)
{
this.pizzaFactory = factory;
}
public Pizza orderPizza(String type)
{
Pizza pizza;
pizza = pizzaFactory.CreatePizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
class PizzaFactory
{
//Pizza orderPizza()
//{
// Pizza pizza;
// Pizza pizza = new Pizza();//若Pizza为具体类?
// pizza.prepare();
// pizza.bake();
// pizza.cut();
// pizza.box();
// //若需要更多的种类,将要添加更多的代码
//}
Pizza pizza = null;//将pizza这个实例提取出来,有利于后面的拓展
public Pizza CreatePizza(String type)
{
if(type.Equals("Cheese"))
{
pizza = new ChessPizza();
}
else if (type.Equals("greek"))
{
pizza = new GreekPizza();
}
else if (type.Equals("pepperoni"))
{
pizza = new PepperoniponiPizza();
}
return pizza;
}
}
下面是其建模过程。
在第一个过程中,PizzaFactory依赖于Pizza,这个时候,当你需要CheesePizza时,我们看看流程,PizzaStore中存有PizzaFactory的实例,通过PizzaFactory创建Pizza,所有的Pizza继承于Pizza基类,因此你可以任意的创建Pizza。
但是这种方式存在的不足是?
如果添加一种新的类型,就必须到工厂中修改代码。
由此,我们有下面改进方式
abstract class PizzaStroe2
{
public Pizza pizza;//创建者并不知道具体的类
public PizzaStroe2()
{
pizza = null;
}
public Pizza orderPizza(String type)
{
pizza = CreatePizza(type);
if (pizza!=null)
{
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
return pizza;
}
public abstract Pizza CreatePizza(String type);//将创建Pizza的方法放入PizzaStore中,可以为不同的地区创建不同的子类。
//使用抽象用以继承,在调用的时候使用多态
}
class NYPizzaStore : PizzaStroe2
{
public override Pizza CreatePizza(String type)//因为或许每个Store的创建方式不一。因此将CreatePizza函数放入到PizzaStore类中
{
if (type.Equals("cheese"))
{
pizza = new NYStrleChessPizza();
}
else if (type.Equals("clams"))
{
pizza = new NYStyleClamPizza();
}
else if (type.Equals("pepperoni"))
{
pizza = new NYStylePepperoniPizza();
}
return pizza;
}
}
abstract class Pizza
{
public String name;
public String dough;
public String sauce;
protected ArrayList toppings = new ArrayList();
public virtual void prepare()
{
Console.WriteLine("Prepareing " + name);
Console.WriteLine("Tossing dough...");
Console.WriteLine("Adding sauce...");
Console.WriteLine("Adding topping:");
foreach (String str in toppings)
{
Console.WriteLine(str);
}
}
public virtual void bake()
{
Console.WriteLine("Bake for 25 minutes at 350");
}
public virtual void cut()
{
Console.WriteLine("Cutting the pizza into diagonal slice");
}
public virtual void box()
{
Console.WriteLine("Place pizza in offical PizzaStore box");
}
public virtual String getName()
{
return name;
}
}
class NYStrleChessPizza : Pizza
{
public NYStrleChessPizza()
{
name = "NY Style and Cheese Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.Add("Grated Reggiano Cheese");
}
public override void prepare()
{
Console.WriteLine("NY Style cheese preparing ");
}
public override void bake()
{
Console.WriteLine("NY Style cheese baking ");
}
public override void cut()
{
Console.WriteLine("NY Style cheese cuting ");
}
public override void box()
{
Console.WriteLine("NY Style cheese preparing ");
}
}
主要的改进是丢弃掉了工厂,工厂主要的职责是创建pizza,提取出来之后,任意类型的Pizza创建属于自己的pizza,此时在Store中的创建为虚函数。个人想法是如果对Factory进行继承,拓展能够实现类似的功能。
看上去我们的代码已经能够实现对修改关闭,对拓展开放的原则,但是我们在创建的时候依旧存在着原料的制约。此时引入一个PizzaIngredientFactory。
interface PizzaIngredientFactory
{
Dough CreateDough();
Sauce CreateSauce();
Cheese CreateCheese();
Pepperoni CreatePepperoni();
Clams CreateClam();
}
class Dough{}
class Sauce{}
class Cheese{}
class Veggies { }
class Clams { }
class Pepperoni { }
class FreshClams : Clams { }
class NYPizzaIngresientFactory : PizzaIngredientFactory
{
public Dough CreateDough()
{
return new Dough();
}
public Sauce CreateSauce()
{
return new Sauce();
}
public Cheese CreateCheese() {
return new Cheese();
}
public Pepperoni CreatePepperoni()
{
return new Pepperoni();
}
public Clams CreateClam()
{
return new FreshClams();//新地域对材料的改进
}
}
abstract class NewPizza:Pizza
{
protected String name;
protected Dough dough;//下面几个都是原材料,对于不同地区对原材料的处理不同.
protected Sauce sauce;
protected Cheese cheese;
protected Pepperoni pepperoi;
protected Clams clams;
public abstract void prepare();
public override void bake()
{
Console.WriteLine("Bake for 25 minutes at 350");
}
public override void cut()
{
Console.WriteLine("Cutting the pizza into digonal slices");
}
public override void box()
{
Console.WriteLine("Place pizza in offical PizzaStore box");
}
public void setName(String name)
{
this.name = name;
}
public override String getName()
{
return name;
}
}
class CheesePizza : NewPizza
{
PizzaIngredientFactory ingredientFactory;//根据不同地区引入不同的处理方式的工厂
public CheesePizza(PizzaIngredientFactory ingredientFactory)
{
this.ingredientFactory = ingredientFactory;
}
public override void prepare()
{
Console.WriteLine("Preparing " + name);
dough = ingredientFactory.CreateDough();
sauce = ingredientFactory.CreateSauce();
cheese = ingredientFactory.CreateCheese();
}
}
class ClamPizza : NewPizza
{
PizzaIngredientFactory ingredientFactory;
public ClamPizza(PizzaIngredientFactory ingredientFactory)
{
this.ingredientFactory = ingredientFactory;
}
public override void prepare()
{
Console.WriteLine("Preparing " + name);
dough = ingredientFactory.CreateDough();
sauce = ingredientFactory.CreateSauce();
clams = ingredientFactory.CreateClam();
}
}
class NewNYPizzaStore : PizzaStroe2
{
public override Pizza CreatePizza(String type)
{
Pizza pizza;
NewPizza newPizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngresientFactory();
if (type.Equals("cheese"))
{
newPizza = new CheesePizza(ingredientFactory);
newPizza.setName("New York Style Cheese Pizza");
}
else if (type.Equals("clams"))
{
newPizza = new ClamPizza(ingredientFactory);
newPizza.setName("New York Style FreshClam Pizza");
}
return newPizza;
}
}
再次看看我们新的建模方式,对于不同的地区有不同的创建方式,此时已经不限于原材料的产地。通过抽象工厂提供的接口,可以创建产品的家族。
4、运行结果:
static void Main(string[] args)
{
PizzaStroe2 nyPizzaStore = new NYPizzaStore();
Pizza pizza = nyPizzaStore.orderPizza("cheese");
Console.WriteLine("Camel ordered a " + pizza.getName());
Console.WriteLine();
PizzaStroe2 newNYPizzaStore = new NewNYPizzaStore();
Pizza clamspizza = newNYPizzaStore.orderPizza("clams");
Console.WriteLine("Camel ordered a " + clamspizza.getName());
Console.ReadLine();
}