定义
定义一个创建对象的接口,但由子类决定要实例的类是哪一个。工厂方法让类把实例推迟到子类。
设计原则
要依赖抽象,不要依赖具体的类:不能让高层组件依赖于底层组件,并且两者都应该依赖于抽象。
指导方针
- 变量不可以持有具体类的引用:如果使用new,就会持有具体类的引用。可以用工厂来避开这样的做法。
- 不要让类派生自具体类:如果派生自具体类,你就会依赖具体类。派生自一个抽象。
- 不要覆盖基类中已实现的方法:如果覆盖基类已实现的方法,那么你的基类就不是一个真正适合被继承的抽象。基类中所有实现的方法,应该由所有子类共享。
抽象工厂模式
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定的具体类。
第一次设计(识别变化)
假设我们有一个披萨店,我们需要写代码来制造一些不同类型的披萨。
下面来看看我们最开始的设计:
Pizza orderPizza(string type)
{
Pizza pizza;
if (type.Equals("cheese"))
{
pizza = new CheesePizza();
}
else if (type.Equals("greek"))
{
pizza = new GreekPizza();
}
else if (type.Equals("pepperoni"))
{
pizza = new PepperoniPizza();
}
else
{
pizza = new Pizza();
}
pizza.perpare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
再这里我们根据type传入的类型来创建对应的pizza,但这里有一个问题,当我们需要修改一些pizza种类的时候,我们就必须要修改里面的代码。比如:不在提供GreekPizza的pizza,我们就必须删除创建GreekPizza的代码。这样就不符合我们的开放-关闭原则。
封装创建对象代码
下面,我们将创建pizza对象代码封装到一个单独的对象中,由这个对象专职创建pizza。
class SimplePizzaFactory
{
public Pizza createPizza(string type)
{
Pizza pizza = null;
if (type.Equals("cheese"))
{
pizza = new CheesePizza();
}
else if (type.Equals("greek"))
{
pizza = new GreekPizza();
}
else if (type.Equals("pepperoni"))
{
pizza = new PepperoniPizza();
}
else
{
pizza = new Pizza();
}
}
}
重做PizzaStore类
class PizzaStore
{
private SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory)
{
this.factory = factory;
}
Pizza orderPizza(string type)
{
Pizza pizza=null;
pizza=factory.createPizza(type);
pizza.perpare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
类图
这种简单的工厂其实并不是一个设计模式,反而比较像是一种编程习惯。
使用框架
下面我们把createPizza的方法放回PizzaStore中,但是要把它设置成"抽象方法",然后为每个区域创建不同的PizzaStore子类。让每个子类各自决定如何制造披萨。
public abstract class PizzaStore
{
//private SimplePizzaFactory factory;
//public PizzaStore(SimplePizzaFactory factory)
//{
// this.factory = factory;
//}
Pizza orderPizza(string type)
{
Pizza pizza = null;
// factory.createPizza(type);
//从工厂对象中移回PizzaStore中
pizza = createPizza(type);
pizza.perpare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
//工厂对象移到这里
public abstract Pizza createPizza(string type);
}
}
在这里,orderPizza会对Pizza对象做许多的事情,但并不知道究竟是哪一种披萨,这里其实就是解耦。
开一家披萨店
public override Pizza createPizza(string type)
{
if (type.Equals("cheese"))
{
return new CheesePizza();
}
//根据类型不同,创建其他对象
return null;
}
工厂模式
所有工厂模式都用来封装对象创建的。
创建者类
Creator类是一个抽象类,它定义了一个抽象的工厂方法,让子类实现此方法制造产品。
子类可以利用createPrizza创建自己的产品。
产品类
对于上面的PizzaStore来说,Pizza就是产品。
定义工厂方法模式
工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推出到子类。
依赖倒置原则
当你直接实例化一个对象时,就是在依赖它的具体类。
在代码里减少对于具体类依赖是件"好事"。这个原则就是依赖倒置原则——要依赖抽象,不要依赖具体类。
不能让高层组件(由其他底层组件定义其行为的类)赖低层组件,不管高层还是底层,两者都应该依赖与抽象。
上面示例应用工厂模式后类图:
可以看到,高层组件(PizzaStore)和底层组件都依赖了Pizza抽象。
几个指导方针帮助你遵循此原则
- 变量不可以持有具体的引用
- 不要让类派生自具体类
- 不要覆盖基类中已经实现的方法