工厂模式(简单工厂、工厂方法、抽象工厂)

时间:2022-10-02 18:53:29

什么是工厂模式?

  顾名思义,用工厂去实例化对象,用工厂方法代替new操作。
  工厂模式包括简单工厂模式、工厂方法模式和抽象工厂模式。

简单工厂模式

  从设计模式的类型上来说,简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

UML图

工厂模式(简单工厂、工厂方法、抽象工厂)

  从UML类图可以看出,简单工厂有三种类,一个是产品基类,一个是产品子类,一个是产品的工厂类。产品工厂类根据不同条件,业务逻辑判断,创建具体的产品对象。

工厂方法模式

  工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

UML图

工厂模式(简单工厂、工厂方法、抽象工厂)

  工厂方法模式相对简单工厂模式最明显的不同,在UML图中显而易见。即工厂类演变成了抽象类,且每个工厂各司其职负责创建一个产品,实现了产品与工厂的解耦。

抽象工厂模式

  为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。

UML图

工厂模式(简单工厂、工厂方法、抽象工厂)

  我们再对比下抽象工厂与工厂方法,不难看出,产品由单一的扩展成为了产品族,而工厂依赖多种产品,加强了对工厂创建产品的扩展。

举个栗子

  下面以披萨项目为例,加深对工厂模式的理解。
  披萨项目:要方便披萨品种的扩展,要便于维护,要能运行时扩展。
  刚开始的披萨有CheesePizza、GreekPizza,用户通过OrderPizza对披萨点单。
Pizza.java

package com.test;

/**
* 披萨抽象类
*/

public abstract class Pizza {
protected String name ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//准备
public abstract void prepare();
//烘焙
public void bake(){
System.out.println(name + " is baking……");
}
//切割
public void cut(){
System.out.println(name + " is cuting……");
}
//装盒
public void box(){
System.out.println(name + " is boxing……");
}
}

CheesePizza.java

package com.test;

/**
* 奶酪披萨
*/

public class CheesePizza extends Pizza {
public CheesePizza(){
this.setName("CheesePizza");
}
@Override
public void prepare() {
System.out.println("prepare Cheese……");
}
}

GreekPizza.java

package com.test;

/**
* 希腊披萨
*/

public class GreekPizza extends Pizza {

public GreekPizza(){
this.setName("GreekPizza");
}
@Override
public void prepare() {
System.out.println("prepare Greek……");
}

}

OrderPizza.java

package com.test;

/**
* 披萨订单
*/

public class OrderPizza {
public OrderPizza(String ordertype){
Pizza pizza = null;
if("cheese".equals(ordertype)){
pizza = new CheesePizza();
}else if("greek".equals(ordertype)){
pizza = new GreekPizza();
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}

public static void main(String[] args) {
new OrderPizza("greek");
}
}

运行结果:

prepare Greek……
GreekPizza is baking……
GreekPizza is cuting……
GreekPizza is boxing……

  这样,简单的根据需求产生披萨的1.0版本就实现了,但是如果要增加一种披萨时,则要增加一个披萨类并且修改OrderPizza类,违背了对扩展的开放、对修改关闭的原则。
  针对以上问题,作以下改进:
  封装变化,将OrderPizza中创建披萨的过程提取成factory工厂类。
 
SimplePizzaFactory.java 创建披萨的工厂类

package com.test.simpleFactory;

import com.test.CheesePizza;
import com.test.GreekPizza;
import com.test.Pizza;

/**
* 简单披萨工厂
*/

public class SimplePizzaFactory {
public Pizza CreatePizza(String orderType){
Pizza pizza = null;
if("cheese".equals(orderType)){
pizza = new CheesePizza();
}else if("greek".equals(orderType)){
pizza = new GreekPizza();
}
return pizza;
}
}

OrderPizza.java

package com.test.simpleFactory;

import com.test.Pizza;

/**
* 披萨订单
*/

public class OrderPizza {
SimplePizzaFactory simplePizzaFactory;
public OrderPizza(String ordertype){
simplePizzaFactory = new SimplePizzaFactory();
Pizza pizza = null;
pizza = simplePizzaFactory.CreatePizza(ordertype);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}

public static void main(String[] args) {
new OrderPizza("greek");
}
}

运行结果:

prepare Greek……
GreekPizza is baking……
GreekPizza is cuting……
GreekPizza is boxing……

  按照简单工厂模式设计的披萨项目2.0版本完成,一个工厂类,一个产品抽象类,和一群实现了产品接口的具体产品,而这个工厂类,根据传入的参数去创造一个具体的实现类,并向上转型为接口作为结果返回。但是仍然存在对修改开放的诟病,继续重构。
PizzaFactory.java

package com.test.factoryMethod;

import com.test.Pizza;

/**
* 披萨工厂抽象类
*/

public abstract class PizzaFactory {
public abstract Pizza CreatePizza(String orderType);
}
KFCPizzaFactory.java
package com.test.factoryMethod;

import com.test.CheesePizza;
import com.test.GreekPizza;
import com.test.Pizza;

KFCPizzaFactory.java

/**
* KFC披萨工厂
*/

public class KFCPizzaFactory extends PizzaFactory {
public Pizza CreatePizza(String orderType){
Pizza pizza = null;
if("cheese".equals(orderType)){
pizza = new CheesePizza();
}else if("greek".equals(orderType)){
pizza = new GreekPizza();
}
return pizza;
}
}

PizzaHutPizzaFactory.java

package com.test.factoryMethod;

import com.test.CheesePizza;
import com.test.GreekPizza;
import com.test.Pizza;

/**
* 必胜客披萨工厂
*/

public class PizzaHutPizzaFactory extends PizzaFactory {
public Pizza CreatePizza(String orderType){
Pizza pizza = null;
if("cheese".equals(orderType)){
pizza = new CheesePizza();
}else if("greek".equals(orderType)){
pizza = new GreekPizza();
}
return pizza;
}
}

OrderPizza.java

package com.test.factoryMethod;

import com.test.Pizza;

/**
* 披萨订单
*/

public class OrderPizza {
PizzaFactory pizzaFactory;
public void KFCOrderPizza(String ordertype){
pizzaFactory = new KFCPizzaFactory();
Pizza pizza = null;
pizza = pizzaFactory.CreatePizza(ordertype);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
public void PizzaHutOrderPizza(String ordertype){
pizzaFactory = new PizzaHutPizzaFactory();
Pizza pizza = null;
pizza = pizzaFactory.CreatePizza(ordertype);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}

public static void main(String[] args) {
OrderPizza order = new OrderPizza();
order.KFCOrderPizza("greek");
order.PizzaHutOrderPizza("greek");
}
}

运行结果

prepare Greek……
GreekPizza is baking……
GreekPizza is cuting……
GreekPizza is boxing……
prepare Greek……
GreekPizza is baking……
GreekPizza is cuting……
GreekPizza is boxing……

 工厂方法模型的实现就完成了,可以看到,我们使用可以随意的在具体的工厂和产品之间切换,并且不需要修改任何代码,就可以让原来的程序正常运行,这也是工厂方法模式对扩展开放的表现,另外工厂方法模式弥补了简单工厂模式不满足开闭原则的诟病,当我们需要增加产品时,只需要增加相应的产品和工厂类,而不需要修改现有的代码。但是目前只针对单一产品,如果要引进“鸡肉”新产品呢?继续改进。
 
Chicken.java

package com.test.abstractFactory;

/**
* 鸡肉抽象类
*/

public abstract class Chicken {
protected String name ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//准备
public abstract void prepare();
//烘焙
public void bake(){
System.out.println(name + " is baking……");
}
//切割
public void cut(){
System.out.println(name + " is cuting……");
}
//装盒
public void box(){
System.out.println(name + " is boxing……");
}
}

FriedChicken.java

package com.test.abstractFactory;

/**
* 炸鸡
*/

public class FriedChicken extends Chicken {

public FriedChicken(){
this.setName("RoastChicken");
}
@Override
public void prepare() {
System.out.println("prepare Chicken……");
}

}

RoastChicken.java

package com.test.abstractFactory;

/**
* 烤鸡
*/

public class RoastChicken extends Chicken {

public RoastChicken(){
this.setName("RoastChicken");
}
@Override
public void prepare() {
System.out.println("prepare Chicken……");
}

}

Factory.java

package com.test.abstractFactory;

import com.test.Pizza;

/**
* 工厂抽象类
*/

public abstract class Factory {
public abstract Pizza CreatePizza(String orderType);
public abstract Chicken CreateChicken(String orderType);
}

KFCFactory.java

package com.test.abstractFactory;

import com.test.CheesePizza;
import com.test.GreekPizza;
import com.test.Pizza;

/**
* KFC工厂
*/

public class KFCFactory extends Factory {
public Pizza CreatePizza(String orderType){
Pizza pizza = null;
if("cheese".equals(orderType)){
pizza = new CheesePizza();
}else if("greek".equals(orderType)){
pizza = new GreekPizza();
}
return pizza;
}

public Chicken CreateChicken(String orderType) {
Chicken chicken = null;
if("fried".equals(orderType)){
chicken = new FriedChicken();
}else if("roast".equals(orderType)){
chicken = new RoastChicken();
}
return chicken;
}
}

PizzaHutFactory.java

package com.test.abstractFactory;

import com.test.CheesePizza;
import com.test.GreekPizza;
import com.test.Pizza;

/**
* 必胜客工厂
*/

public class PizzaHutFactory extends Factory {
public Pizza CreatePizza(String orderType){
Pizza pizza = null;
if("cheese".equals(orderType)){
pizza = new CheesePizza();
}else if("greek".equals(orderType)){
pizza = new GreekPizza();
}
return pizza;
}
public Chicken CreateChicken(String orderType) {
Chicken chicken = null;
if("fried".equals(orderType)){
chicken = new FriedChicken();
}else if("roast".equals(orderType)){
chicken = new RoastChicken();
}
return chicken;
}
}

OrderPizza.java

package com.test.abstractFactory;

import com.test.Pizza;

/**
* 订单
*/

public class OrderPizza {
Factory Factory;
public void KFCOrderPizza(String ordertype){
Factory = new KFCFactory();
Pizza pizza = null;
pizza = Factory.CreatePizza(ordertype);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
public void KFCOrderChicken(String ordertype){
Factory = new KFCFactory();
Chicken chicken = null;
chicken = Factory.CreateChicken(ordertype);
chicken.prepare();
chicken.bake();
chicken.cut();
chicken.box();
}
public void PizzaHutOrderPizza(String ordertype){
Factory = new PizzaHutFactory();
Pizza pizza = null;
pizza = Factory.CreatePizza(ordertype);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}

public static void main(String[] args) {
OrderPizza order = new OrderPizza();
order.KFCOrderPizza("greek");
order.PizzaHutOrderPizza("greek");
}
}

  与工厂方法对比下就发现,多了一个产品系列叫Chinken,工厂接口里多了一个方法,叫CreateChicken,所以抽象工厂模式就是工厂方法模式添加了抽象产品所演变而来的。

总结

  1,首先从简单工厂进化到工厂方法,是因为工厂方法弥补了简单工厂对修改开放的弊端,即简单工厂违背了开闭原则。
  2,从工厂方法进化到抽象工厂,是因为抽象工厂弥补了工厂方法只能创造一个系列的产品的弊端。

参考文章:
http://www.cnblogs.com/zuoxiaolong/p/pattern5.html (工厂方法)