工厂模式
在现实生活中社会分工越来越细,越来越专业化。各种产品有专门的工厂生产,彻底告别了自给自足的小农经济时代,这大大缩短了产品的生产周期,提高了生产效率。同样,在软件开发中能否做到软件对象的生产和使用相分离呢?能否在满足“开闭原则”的前提下,客户随意增删或改变对软件相关对象的使用呢?这就是本节要讨论的问题。
定义
工厂模式定义了一个创建对象的接口(抽象基类),但由子类决定要示例化的类是哪一个。工厂方法模式让类把实例化推迟到子类。
UML类图
使用场景
1.客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
2.创建产品的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
3.客户不关心创建产品的细节,只关心产品的品牌。
示例
以下是工厂类:
Pizza工厂基类
/**
* 产品工厂基类
*/
public abstract class PizzaFactory {
/**
* 根据Type创建不同的产品
*
* @param type 产品类型
* @return
*/
public Pizza createProduct(String type) {
Pizza pizza;
// 生产Pizza产品
pizza = createPizza(type);
// 对Pizza产品做一些操作
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
// 返回生产的产品
return pizza;
}
protected abstract Pizza createPizza(String type);
}
纽约Pizza工厂
/**
* 纽约Pizza工厂
*/
public class NYPizzaFactory extends PizzaFactory {
@Override
protected Pizza createPizza(String type) {
Pizza pizza = null;
switch (type) {
case "Cheese":
pizza = new NYStlyeCheesePizza();
break;
case "Clam":
pizza = new NYStyleClamPizza();
break;
}
return pizza;
}
}
芝加哥Pizza工厂
/**
* 芝加哥Pizza工厂
*/
public class ChicagoPizzaFactory extends PizzaFactory {
@Override
protected Pizza createPizza(String type) {
Pizza pizza= null;
switch (type){
case "Cheese":
pizza = new ChicagoCheesePizza();
break;
case "Clam":
pizza = new ChicagoClamPizza();
break;
}
return pizza;
}
}
以下是产品类:
Pizza基类
/**
* 披萨基类
*/
public class Pizza {
protected String name; // 名称
protected String dough; // 面团
protected String sauce; // 酱料
protected List<String> topping = new ArrayList(); // 配料
public void prepare() {
// 准备
System.out.println("正在准备的Pizza:" + name);
}
public void bake() {
// 烘培
System.out.println("烘培需要30分钟..");
}
public void cut() {
// 切片
System.out.println("正在切片...");
}
public void box() {
// 装盒
System.out.println("Pizza装进方盒..");
}
public String getName() {
return name;
}
}
纽约奶酪Pizza
/**
* 纽约奶酪Pizza
*/
public class NYStlyeCheesePizza extends Pizza {
public NYStlyeCheesePizza(){
name = "纽约奶酪Pizza";
dough = "纽约面团";
sauce = "纽约酱料";
topping.add("纽约佐料");
}
@Override
public void cut(){
System.out.println("纽约奶酪Pizza要切成圆形...");
}
}
纽约蛤蜊Pizza
/**
* 纽约蛤蜊Pizza
*/
public class NYStyleClamPizza extends Pizza {
public NYStyleClamPizza(){
name = "纽约蛤蜊Pizza";
dough = "纽约面团";
sauce = "纽约酱料";
topping.add("纽约佐料");
}
@Override
public void cut(){
System.out.println("纽约蛤蜊Pizza要切成圆形...");
}
}
芝加哥奶酪Pizza
/**
* 芝加哥奶酪Pizza
*/
public class ChicagoCheesePizza extends Pizza {
public ChicagoCheesePizza(){
name = "芝加哥奶酪Pizza";
dough = "芝加哥面团";
sauce = "芝加哥酱料";
topping.add("芝加哥佐料");
}
@Override
public void cut(){
System.out.println("芝加哥奶酪Pizza要切成方形...");
}
}
芝加哥蛤蜊Pizza
/**
* 芝加哥蛤蜊Pizza
*/
public class ChicagoClamPizza extends Pizza {
public ChicagoClamPizza(){
name = "芝加哥蛤蜊Pizza";
dough = "芝加哥面团";
sauce = "芝加哥酱料";
topping.add("芝加哥佐料");
}
@Override
public void cut(){
System.out.println("芝加哥蛤蜊Pizza要切成方形...");
}
}
测试:
/**
* 测试
*/
public class Test {
public static void main(String[] args) {
// 用纽约Pizza工厂生产一个纽约蛤蜊Pizza
NYPizzaFactory nyPizzaFactory = new NYPizzaFactory();
Pizza nyClamPizza = nyPizzaFactory.createProduct("Clam");
// 用芝加哥Pizza工厂生产一个芝加哥奶酪Pizza
ChicagoPizzaFactory chicagoPizzaFactory = new ChicagoPizzaFactory();
Pizza chicagoCheesePizza = chicagoPizzaFactory.createProduct("Cheese");
}
}
结果:
正在准备的Pizza:纽约蛤蜊Pizza
烘培需要30分钟..
纽约蛤蜊Pizza要切成圆形...
Pizza装进方盒..
正在准备的Pizza:芝加哥奶酪Pizza
烘培需要30分钟..
芝加哥奶酪Pizza要切成方形...
Pizza装进方盒..
优缺点
优点:
1.用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
2.灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
3.典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
1.类的个数容易过多,增加复杂度。
2.增加了系统的抽象性和理解难度。
3.抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。
工作中的应用
敬请期待
设计原则工具箱
1.找出应用中可能需要变化的部分,把它们独立出来,不要和那些不需要变化的代码混合在一起
2.针对接口(超类型)编程而不是针对具体的实现编程
3.多用组合少用继承
4.为了交互对象之间的松耦合设计而努力
5.类应该对扩展开放,对修改关闭
6.依赖抽象,不要依赖具体类。(即不要让高层组件依赖低层组件,而且不管高层组件还是低层组件都应该依赖于抽象)