工厂模式有简单工厂模式,工厂方法模式,抽象工厂模式三类。
开始介绍工厂模式之前,先分析一个小案例:一个简单的披萨项目,要便于披萨种类的扩展,便于维护。要求如下:
(1)披萨种类很多,有GreekPizza,CheesePizza等等。
(2)披萨的制作过程为prepare,bake,cut,box。
(3)完成披萨的订购功能。
对上述要求,用传统方式实现如下:
// 准备一个抽象得Pizza类,提供四个制作步骤
public abstract class Pizza {
protected String name;
public abstract void prepare();
public void bake() {
System.out.println(name + " baking");
}
public void cut() {
System.out.println(name + " cutting");
}
public void box() {
System.out.println(name + " boxing");
}
public void setName(String name) {
this.name = name;
}
}
// 不同种类的Pizza分别继承上述抽象类,重写prepare方法(不同种类的披萨所需材料不同)
public class CheesePizza extends Pizza {
@Override
public void prepare() {
System.out.println("prepare CheesePizza");
}
}
public class GreekPizza extends Pizza {
@Override
public void prepare() {
System.out.println("prepare GreekPizza");
}
}
// 订购披萨
public class OrderPizza {
public OrderPizza() {
Pizza pizza = null;
String pizzaType;
do {
pizzaType = getType();
if ("Greek".equals(pizzaType)) {
pizza = new GreekPizza();
pizza.setName("GreekPizza");
} else if ("Cheese".equals(pizzaType)) {
pizza = new CheesePizza();
pizza.setName("CheesePizza");
} else {
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while(true);
}
// 获取需要订购的披萨种类
private String getType() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type:");
return reader.readLine();
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
// 主函数
public static void main(String[] args) {
new OrderPizza();
}
对上述方法做如下分析:
(1)容易理解,简单易操作。
(2)违反了开闭原则,即对扩展开放,对修改关闭。在这种实现方式中,如果增加一个新的披萨种类,首先要增加一个类去继承Pizza类,还需要在OrderPizza类中增加判断功能,而且,如果有多个OrderPizza类(可以有很多地方订购),则需要修改更多的地方。综上,要新增一个披萨种类,不仅需要修改客户端,还需修改服务端。
(3)针对上述问题可以做以下修改:将创建Pizza对象的操作封装为一个类,如果增加新的披萨种类,只需修改该类即可,这便是简单工厂模式。
简单工厂模式
基本介绍
(1)简单工厂模式是属于创建型模式,是工厂模式的一种,简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
(2)简单工厂模式为定义一个创建对象的类,由这个类来封装实例化对象的行为。
(3)软件开发中,当我们会用到大量的创建某种,某类或者某批对象时,就会用到工厂模式。(JDK中,Calendar类为使用了简单工厂模式的典型实例)。
实例分析
针对上述实例,我们分析了存在的问题以及修改方式,具体的修改实现如下:
// 将实例化对象的操作封装为一个类
public class SimpleFactory {
public Pizza createPizza(String pizzaType) {
Pizza pizza = null;
if ("Greek".equals(pizzaType)) {
pizza = new GreekPizza();
pizza.setName("GreekPizza");
} else if ("Cheese".equals(pizzaType)) {
pizza = new CheesePizza();
pizza.setName("CheesePizza");
}
return pizza;
}
}
// 订购披萨
public class OrderPizza {
Pizza pizza = null;
public OrderPizza(SimpleFactory simpleFactory) {
setSimpleFactory(simpleFactory);
}
public void setSimpleFactory (SimpleFactory simpleFactory) {
String pizzaType = "";
do {
pizzaType = getType();
pizza = simpleFactory.createPizza(pizzaType);
if (pizza != null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
break;
}
} while(true);
}
}
// 主方法
public static void main(String[] args) {
new OrderPizza(new SimpleFactory());
}
为了减少代码量,可以将实例化对象的操作封装为一个静态方法,具体修改如下:
public class SimpleFactory {
public static Pizza createPizza(String pizzaType) {
Pizza pizza = null;
if ("Greek".equals(pizzaType)) {
pizza = new GreekPizza();
pizza.setName("GreekPizza");
} else if ("Cheese".equals(pizzaType)) {
pizza = new CheesePizza();
pizza.setName("CheesePizza");
}
return pizza;
}
}
public class OrderPizza {
String pizzaType = "";
Pizza pizza = null;
public OrderPizza() {
do {
pizzaType = getType();
pizza = SimpleFactory.createPizza(pizzaType);
if (pizza != null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
break;
}
} while(true);
}
}
public static void main(String[] args) {
new OrderPizza();
}
工厂方法模式
基本介绍
定义一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到了子类。
实例分析
针对上述实例,现增加一个新的需求:客户在点披萨时,可以点不同口味的披萨,比如:北京的CheesePizza,北京的PapperPizza或者上海的CheesePizza,上海的PapperPizza。对此需求,可以有如下两个思路进行修改:
思路一:
使用简单工厂模式,创建不同的简单工厂类,比如:BJPizzaFactory、SHPizzaFactory等等。此方法对当前案例来说,可以使用,但是考虑到项目规模,以及软件的可维护性,可扩展性并不是特别好。(例如:如果有多个PizzaFactory)。
思路二:使用工厂方法模式,将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
针对思路二,具体实现如下:
新增BJPapperPizza,BJCheesePizza,SHPapperPizza,SHCheesePizza继承Pizza类。
public class BJCheesePizza extends Pizza{
@Override
public void prepare() {
setName("BJCheesePizza");
System.out.println("prepare BJCheesePizza");
}
}
public class BJPapperPizza extends Pizza{
@Override
public void prepare() {
setName("BJPapperPizza");
System.out.println("prepare BJPapperPizza");
}
}
public class SHCheesePizza extends Pizza {
@Override
public void prepare() {
setName("SHCheesePizza");
System.out.println("prepare SHCheesePizza");
}
}
public class SHPapperPizza extends Pizza{
@Override
public void prepare() {
setName("SHPapperPizza");
System.out.println("prepare SHPapperPizza");
}
}
// 将订购披萨功能改为抽象化
public abstract class OrderPizza {
// 提供创建对象的抽象方法
abstract Pizza createPizza(String pizzaType);
public OrderPizza() {
Pizza pizza = null;
String pizzaType;
do {
pizzaType = getType();
pizza = createPizza(pizzaType);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while(true);
}
}
// 根据不同的需求,在子类中具体实现抽象方法
public class BJOrderPizza extends OrderPizza{
@Override
Pizza createPizza(String pizzaType) {
Pizza pizza = null;
if ("Cheese".equals(pizzaType)) {
pizza = new BJCheesePizza();
} else if ("Papper".equals(pizzaType)) {
pizza = new BJPapperPizza();
}
return pizza;
}
}
public class SHOrderPizza extends OrderPizza{
@Override
Pizza createPizza(String pizzaType) {
Pizza pizza = null;
if ("Cheese".equals(pizzaType)) {
pizza = new SHCheesePizza();
} else if ("Papper".equals(pizzaType)) {
pizza = new SHPapperPizza();
}
return pizza;
}
}
// 主方法
public static void main(String[] args) {
// new BJOrderPizza();
new SHOrderPizza();
}
对以上所述实例的实现可以进一步使用抽象工厂模式进行修改,具体如下所所述:
抽象工厂模式
基本介绍
(1)定义一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类。
(2)抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
(3)从设计层面上看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。
(4)将工厂抽象为两层,AbsFactory(抽象工厂)和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
实例分析
// 添加一个创建实例的抽象工厂
public interface AbsFactory {
public Pizza createPizza(String orderType);
}
// 根据要求使用具体的工厂子类去实现创建对象的操作
public class BJFactory implements AbsFactory{
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if ("Papper".equals(orderType)) {
pizza = new BJPapperPizza();
} else if ("Cheese".equals(orderType)) {
pizza = new BJCheesePizza();
}
return pizza;
}
}
public class SHFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if ("Papper".equals(orderType)) {
pizza = new SHPapperPizza();
} else if ("Cheese".equals(orderType)) {
pizza = new SHCheesePizza();
}
return pizza;
}
}
public class OrderPizza {
public OrderPizza(AbsFactory absFactory) {
setFactory(absFactory);
}
private void setFactory(AbsFactory absFactory) {
Pizza pizza = null;
String pizzaType = "";
do {
pizzaType = getType();
pizza = absFactory.createPizza(pizzaType);
if (pizza != null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
} while(true);
}
}
public static void main(String[] args) {
// new OrderPizza(new BJFactory());
new OrderPizza(new SHFactory());
}