设计模式:简单工厂

工厂方法应该是用得非常多的设计模式,随处可见Factory,简单工厂其实不算一个真正的设计模式

Head First里以Java多态引出问题

Duck duck;

if (picnic) {
duck = new MallardDuck();
} else if (hunting) {
duck = new DecoyDuck();
} else if (inBathTub) {
duck = new RubberDuck();
}

duck.display();
duck.performFly();
duck.performQuack();
duck.swim();

这里分支结构里根据条件判断,来决定实例化哪一个鸭子对象,而这个条件比较恶心,不好扩展,多一种分支条件,就必要进行添加修改以及检查,而其实后面方法的调用其实是不受影响的,因此如果能够做一下分离,封装就完美了

工厂类拥有一个工厂方法,接受了一个参数,通过不同的参数实例化不同的产品类

 

首先看一段Python实现改写,例子还是披萨,先通过python熟悉下整个流程比较简单

比如买一个原味披萨,需要进行下面流程

class Pizza(object):
def prepare(self):
return "prepare pizza"
def bake(self):
return "bake pizza"
def cut(self):
return "cut pizza"
def box(self):
return "box pizza"

披萨店买披萨,店家要提供披萨,大致有这些流程

class PizzaStore(object):
def order_pizza(self):
pizza = Pizza()

print pizza.prepare()
print pizza.bake()
print pizza.cut()
print pizza.box()

比如当前披萨店里有下列三种类型披萨

class CheesePizza(object):
def prepare(self):
return "prepare CheesePizza"
def bake(self):
return "bake CheesePizza"
def cut(self):
return "cut CheesePizza"
def box(self):
return "box CheesePizza"

class GreekPizza(object):
def prepare(self):
return "prepare GreekPizza"
def bake(self):
return "bake GreekPizza"
def cut(self):
return "cut GreekPizza"
def box(self):
return "box GreekPizza"

class PepperoniPizza(object):
def prepare(self):
return "prepare PepperoniPizza"
def bake(self):
return "bake PepperoniPizza"
def cut(self):
return "cut PepperoniPizza"
def box(self):
return "box PepperoniPizza"

一下子就有三种类型可选,那么根据用户的选择类型,来实例化不同的类,最终按要求切,烤,包装相应类型的披萨,这些操作一般是不变的

class PizzaStore(object):
def __init__(self, type):
self.type = type
def order_pizza(self):
if self.type == "CHEESE":
pizza = CheesePizza()
elif self.type == "GREEK":
pizza = GreekPizza()
elif self.type == "PEPPERONI":
pizza = PepperoniPizza()

print pizza.prepare()
print pizza.bake()
print pizza.cut()
print pizza.box()

这样就形成了一个恶性循环,披萨店假如要继续扩张,继续优化产品,只要类型增加,orderPizza方法都要进行修改,关键还只是部分修改

在这种前提下,可以将不断变化需要修改的部分移到另一个对象当中,返回不同的实例

这部分变化,可以通过一个工厂里的create_pizza实现封装起来,返回特有类型的实例

class SimplePizzaFactory(object):
def create_pizza(self, type):
if type == "CHEESE":
pizza = CheesePizza()
elif type == "GREEK":
pizza = GreekPizza()
elif type == "PEPPERONI":
pizza = PepperoniPizza()
return pizza

将工厂传进来,具体类型按照传入的type交给工厂方法去做了,返回pizza的实例,做好了然后进行烤,切,包装

class PizzaStore(object):
def __init__(self):
self.factory = PizzaFactory()
def order_pizza(self, type):
pizza = self.factory.create_pizza(type)
print pizza.prepare()
print pizza.bake()
print pizza.cut()
print pizza.box()

上面的例子综合起来,完整python源码

# /usr/bin/env python
# -*- coding: utf-8 -*-

class CheesePizza(object):
def prepare(self):
return "prepare CheesePizza"
def bake(self):
return "bake CheesePizza"
def cut(self):
return "cut CheesePizza"
def box(self):
return "box CheesePizza"

class GreekPizza(object):
def prepare(self):
return "prepare GreekPizza"
def bake(self):
return "bake GreekPizza"
def cut(self):
return "cut GreekPizza"
def box(self):
return "box GreekPizza"

class PepperoniPizza(object):
def prepare(self):
return "prepare PepperoniPizza"
def bake(self):
return "bake PepperoniPizza"
def cut(self):
return "cut PepperoniPizza"
def box(self):
return "box PepperoniPizza"

class SimplePizzaFactory(object):
def create_pizza(self, type):
if type == "CHEESE":
pizza = CheesePizza()
elif type == "GREEK":
pizza = GreekPizza()
elif type == "PEPPERONI":
pizza = PepperoniPizza()
return pizza

class PizzaStore(object):
def __init__(self):
self.factory = SimplePizzaFactory()
def order_pizza(self, type):
pizza = self.factory.create_pizza(type)
print pizza.prepare()
print pizza.bake()
print pizza.cut()
print pizza.box()

if __name__ == '__main__':
p = PizzaStore()
p.order_pizza('GREEK')

 综合来看,工厂类SimplePizzaFactory就专门创建各种披萨,与此同时,PizzaStore也变成了工厂类的客户,当披萨店有人想买GREK类型的披萨,PizzaStore就呼叫了下工厂SimplePizzaFactory,告知需要的种类,委托工厂的order_pizza方法来完成制作,最终返回锁需要类型的披萨实例

这种模式看上去比较简单,也就将部分环节封装到了一个类里,工厂方法依据传入的参数,生成对应的具体对象实例,这种方式就是简单工程模式

 

下面是原汁原味的简单工厂Java描述

首先定义了一个抽象Pizza类

package factory;

/**
* @author lihui
* @date 2018/4/9 12:01
*/
public abstract class Pizza {

void prepare() {}
void bake() {}
void cut() {}
void box() {}
}

同样,有三种具体类型的披萨,继承了Pizza类,并且实现了它的方法

CheesePizza

package factory;

/**
* @author lihui
* @date 2018/4/9 12:05
*/
public class CheesePizza extends Pizza {

void prepare() {
System.out.println("CheesePizza prepare");
}

void bake() {
System.out.println("CheesePizza bake");
}

void cut() {
System.out.println("CheesePizza cut");
}

void box() {
System.out.println("CheesePizza box");
}
}

GreekPizza

package factory;

/**
* @author lihui
* @date 2018/4/9 12:06
*/
public class GreekPizza extends Pizza {

void prepare() {
System.out.println("GreekPizza prepare");
}

void bake() {
System.out.println("GreekPizza bake");
}

void cut() {
System.out.println("GreekPizza cut");
}

void box() {
System.out.println("GreekPizza box");
}
}

PepperoniPizza

package factory;

/**
* @author lihui
* @date 2018/4/9 12:06
*/
public class PepperoniPizza extends Pizza {

void prepare() {
System.out.println("PepperoniPizza prepare");
}

void bake() {
System.out.println("PepperoniPizza bake");
}

void cut() {
System.out.println("PepperoniPizza cut");
}

void box() {
System.out.println("PepperoniPizza box");
}
}

披萨店里需要做披萨,然后卖出;对比上面Python实现,同样,也要根据需求披萨的类型,实例化具体的类,赋给pizza实例变量,最终返回

package factory;

/**
* @author lihui
* @date 2018/4/9 12:09
*/
public class PizzaStore {
public Pizza orderPizza(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();
}

pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();

return pizza;
}
}

中间实例化部分是随时都会改变的,而后面的包装,烤,切基本不会变,因此可以将中间实例化创建披萨的代码放到另一个类里,需要创建一个什么样的披萨,都交给这个工厂类来完成

package factory;

/**
* @author lihui
* @date 2018/4/9 12:36
*/
public 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();
}

return pizza;
}
}

现在有了SimplePizzaFactory,orderPizza()就成了对象的客户,需要披萨,就找工厂,得到一个实现了Pizza接口的披萨

这样有任何需要修改的地方,只需要修改这个工厂类即可,除此之外,还可以有其他方法也都通过这个工厂类来处理

这时候PizzaStore需要修改

package factory;

/**
* @author lihui
* @date 2018/4/9 12:09
*/
public class PizzaStore {
SimplePizzaFactory factory;

public PizzaStore(SimplePizzaFactory factory) {
this.factory = factory;
}

public Pizza orderPizza(String type) {
Pizza pizza;

pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();

return pizza;
}
}

首先定义了一个SimplePizzaFactory类型的引用,构造函数里传入一个工厂作为参数;这样orderPizza通过传入的类型参数,通过传入的工厂来调用其工厂方法,就能创建指定类型的披萨

如果要执行该流程,可以添加个main方法,注意工厂是作为参数传入PizzaStore的

package factory;

/**
* @author lihui
* @date 2018/4/9 12:27
*/
public class Main {
public static void main(String[] args) {
SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory();
PizzaStore pizzaStore = new PizzaStore(simplePizzaFactory);
pizzaStore.orderPizza("greek");
}
}

设计模式里,所谓的“实现一个接口”,并不一定表示“写一个类,并利用implement关键字来实现某个Java接口”;“实现一个接口”泛指“实现某个超类型(可以使类或者接口)的某个方法

上面这段话摘自《Head First设计模式》工厂模式某一页不起眼的最下方,写的挺好

发表回复