文章目录
一、工厂模式简介
工厂方法模式同样属于类的创建型模式又被称为多态工厂模式 。工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
二、工厂模式的结构
三、工厂模式的角色及职责
1.抽象工厂(Creator)角色:工厂方法模式的核心,任何工厂类都必须实现这个接口。
2.具体工厂( Concrete Creator)角色:具体工厂类是抽象工厂的一个实现,负责实例化产品对象。
3.抽象(Product)角色:工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
4.具体产品(Concrete Product)角色:工厂方法模式所创建的具体实例对象
四、工厂模式的实现
现在我们的主人公嘉纹想要开一家披萨店,而且已经花了好长时间学习制作披萨。。
1、不使用工厂模式
嘉纹花大价钱买了一整套做披萨的流水线。下面这个流水线能做出各种披萨:
直接定义一个抽象批萨类,仅将准备的部分作为实现部分
package design.factory.gys.Pizza;
public abstract class Pizza {
private String name;
public Pizza() {};
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract void prepare() ;
public void bake() {
System.out.println(name+" is baking");
}
public void cut() {
System.out.println(name+" is cutting");
}
public void box() {
System.out.println(name+" is boxing");
}
public void finished() {
System.out.println(name+" has finished");
}
}
流水线虽然贵,但是嘉纹还只会做两种披萨。
一种是PanPizza:
// An highlighted block
package design.factory.gys.Pizza;
public class PanPizza extends Pizza{
@Override
public void prepare() {
// TODO Auto-generated method stub
System.out.println(this.getName()+" is preparing");
}
}
另外一种就是ThickPizza:
// An highlighted block
package design.factory.gys.Pizza;
public class ThickPizza extends Pizza{
@Override
public void prepare() {
// TODO Auto-generated method stub
System.out.println(this.getName()+" is preparing");
}
}
由于刚开业,顾客不是很多,嘉纹也没有雇佣别人,也就简单的手写订单然后自己做披萨:
直接将批萨类的字节码设置成数组对象,每次从中随机
选取一个字节码使用newInstance()方法创建视题对象,
通过getClass()、getSimpleName()方法获取pizza的
实际类对象的名字,并调用setName()进行名称设置
package design.factory.gys.nofactory;
import java.util.Random;
import design.factory.gys.Pizza.PanPizza;
import design.factory.gys.Pizza.Pizza;
import design.factory.gys.Pizza.ThickPizza;
public class OrderPizza {
@SuppressWarnings("rawtypes")
private static Class[] types= new Class[]{PanPizza.class,ThickPizza.class};
private static Random rand=new Random();
public OrderPizza() {};
public void start(){
Class<Pizza> type=types[rand.nextInt(types.length)];
Pizza pizza = null;
try {
pizza = (Pizza)type.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String name=pizza.getClass().getSimpleName();
pizza.setName(name);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
pizza.finished();
}
}
开门大吉:
// An highlighted block
package design.factory.gys.nofactory;
public class PizzaStore {
public static void main(String[] args) {
OrderPizza order =new OrderPizza();
order.start();
System.out.println("-------------");
order.start();
}
}
我们来看看第一天嘉纹的营业情况:
// An highlighted block
ThickPizza is preparing
ThickPizza is baking
ThickPizza is cutting
ThickPizza is boxing
ThickPizza has finished
-------------
PanPizza is preparing
PanPizza is baking
PanPizza is cutting
PanPizza is boxing
PanPizza has finished
看样子还不错,客人点了嘉纹的拿手披萨各一份。好吧,希望她生意红火。
2、简单工厂模式
过了不久,客人都觉得嘉纹做的披萨好吃,生意越来越好,而且嘉纹学会了另外一种披萨CrackerandThinPizza:
// An highlighted block
package design.factory.gys.Pizza;
public class CrackerandThinPizza extends Pizza{
@Override
public void prepare() {
// TODO Auto-generated method stub
System.out.println(this.getName()+" is preparing");
}
}
这时候嘉纹只能雇佣一些人(我们就叫简单工厂)帮忙做披萨:
这个工厂我们只返回newInstance()创建的Pizza对象,
所有的制作过程都在点单系统上显现。
package design.factory.gys.simplefactory;
import java.util.Random;
import design.factory.gys.Pizza.CrackerandThinPizza;
import design.factory.gys.Pizza.PanPizza;
import design.factory.gys.Pizza.Pizza;
import design.factory.gys.Pizza.ThickPizza;
public class PIzzaFactory {
private static Class[] types= new Class[]{PanPizza.class,ThickPizza.class,CrackerandThinPizza.class};
private static Random rand=new Random();
public Pizza getPizza() {
Class<Pizza> type=types[rand.nextInt(types.length)];
Pizza pizza = null;
try {
pizza = (Pizza)type.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String name=pizza.getClass().getSimpleName();
pizza.setName(name);
return pizza;
}
}
每次嘉纹点完单,就通过getPizza()告诉员工并让员工送到服务台。下面我们看看她的点单情况:
通过工厂类中的getPizza()方法,获取一个Pizza对象,
然后进行一系列的操作。
package design.factory.gys.simplefactory;
import design.factory.gys.Pizza.Pizza;
public class OrderPizza {
private PIzzaFactory factory;
public OrderPizza(PIzzaFactory factory) {
super();
this.factory = factory;
}
public void setFactory(PIzzaFactory factory) {
this.factory = factory;
}
public void start() {
Pizza pizza=factory.getPizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
pizza.finished();
}
}
看看今天披萨店收入如何:
这里我们需要传入一个工厂对象,通过start()方法进行烘焙
package design.factory.gys.simplefactory;
public class PizzaStore {
public static void main(String[] args) {
// TODO Auto-generated method stub
new OrderPizza(new PIzzaFactory()).start();;
}
}
// An highlighted block
CrackerandThinPizza is preparing
CrackerandThinPizza is baking
CrackerandThinPizza is cutting
CrackerandThinPizza is boxing
CrackerandThinPizza has finished
看来刚出的披萨要大卖一阵了。
3、工厂方法模式
嘉纹很努力的工作了一阵时间,挣了钱,打算在纽约另外开一家分店,于是设计了下面的点单模式:
设计一个抽象的类,子类继承OrderPizza类,并重写抽象方法
setPizza(),每个子类返回的Pizza类都在内部定义了全部范
围。返回Pizza类型之后,通过调用父类的start()方法,每个
工厂都能进行披萨制作了。
package design.factory.gys.factorymethod;
import design.factory.gys.Pizza.Pizza;
public abstract class OrderPizza {
public OrderPizza () {};
public abstract Pizza setPizza();
public void start()
{
Pizza pizza=setPizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
pizza.finished();
}
}
嘉纹给原来的伦敦分店和新的纽约分店进行了不一样的设计,主要是两各分店经营的披萨不同,都是两种。
伦敦分店主要售卖PanPizza和ThickPizza:
// An highlighted block
package design.factory.gys.factorymethod;
import java.util.Random;
import design.factory.gys.Pizza.PanPizza;
import design.factory.gys.Pizza.Pizza;
import design.factory.gys.Pizza.ThickPizza;
public class LondonOrder extends OrderPizza{
private static Class[] types= new Class[]{PanPizza.class,ThickPizza.class};
private static Random rand=new Random();
@Override
public Pizza setPizza() {
// TODO Auto-generated method stub
Class<Pizza> type=types[rand.nextInt(types.length)];
Pizza pizza = null;
try {
pizza = (Pizza)type.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String name=pizza.getClass().getSimpleName();
pizza.setName(name);
return pizza;
}
}
纽约分店主要售卖CrackerandThinPizza和TakeandBakePizza:
// An highlighted block
package design.factory.gys.factorymethod;
import java.util.Random;
import design.factory.gys.Pizza.CrackerandThinPizza;
import design.factory.gys.Pizza.Pizza;
import design.factory.gys.Pizza.TakeandBakePizza;
public class NewyorkOrder extends OrderPizza{
private static Class[] types= new Class[]{CrackerandThinPizza.class,TakeandBakePizza.class};
private static Random rand=new Random();
@Override
public Pizza setPizza() {
// TODO Auto-generated method stub
Class<Pizza> type=types[rand.nextInt(types.length)];
Pizza pizza = null;
try {
pizza = (Pizza)type.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String name=pizza.getClass().getSimpleName();
pizza.setName(name);
return pizza;
}
}
让我们看一下现在的经营状况:
// An highlighted block
package design.factory.gys.factorymethod;
public class PizzaStore {
public static void main(String[] args) {
new LondonOrder().start();
System.out.println("--------------");
new NewyorkOrder().start();
}
}
// An highlighted block
PanPizza is preparing
PanPizza is baking
PanPizza is cutting
PanPizza is boxing
PanPizza has finished
--------------
CrackerandThinPizza is preparing
CrackerandThinPizza is baking
CrackerandThinPizza is cutting
CrackerandThinPizza is boxing
CrackerandThinPizza has finished
看来我们的嘉纹还是很有经商头脑的,两家店经营的都很不错。生意越来约好了,嘉纹就开始考虑开更多的分店的事了,总不能给每一个分店设计一个点单系统吧,所以,嘉纹就找到我们帮她设计。
4、抽象工厂模式
首先我们设计一个抽象的点单的接口:
// 抽象工厂其实就是将工厂抽象成一个接口,以后需要更多的工厂类的时候,直接扩展接口就好
package design.factory.gys.factories;
import java.util.Random;
import design.factory.gys.Pizza.Pizza;
public abstract class PizzaFactory {
public static Random rand=new Random();
public abstract Pizza getPizza();
}
这样我们嘉纹就能从这个接口开设更多的分店了。下面看看现在伦敦和纽约的分店情况。
伦敦分店:
// An highlighted block
package design.factory.gys.factories;
import design.factory.gys.Pizza.PanPizza;
import design.factory.gys.Pizza.Pizza;
import design.factory.gys.Pizza.ThickPizza;
public class Londonfactory extends PizzaFactory{
private static Class[] types= new Class[]{PanPizza.class,ThickPizza.class};
@Override
public Pizza getPizza() {
// TODO Auto-generated method stub
Class<Pizza> type=types[rand.nextInt(types.length)];
Pizza pizza = null;
try {
pizza = (Pizza)type.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String name=pizza.getClass().getSimpleName();
pizza.setName(name);
return pizza;
}
}
纽约分店:
// An highlighted block
package design.factory.gys.factories;
import design.factory.gys.Pizza.CrackerandThinPizza;
import design.factory.gys.Pizza.Pizza;
import design.factory.gys.Pizza.TakeandBakePizza;
public class Newyorkfactory extends PizzaFactory{
private static Class[] types= new Class[]{CrackerandThinPizza.class,TakeandBakePizza.class};
@Override
public Pizza getPizza() {
// TODO Auto-generated method stub
Class<Pizza> type=types[rand.nextInt(types.length)];
Pizza pizza = null;
try {
pizza = (Pizza)type.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String name=pizza.getClass().getSimpleName();
pizza.setName(name);
return pizza;
}
}
至于点单系统我们按照原来的方案,但是对提供了一个对于不同餐厅的方法。
这里传入的是接口的子类对象,该构造方法不管子类的具体实现
这样就容易实现工厂接口的扩展,而不用改动OrderPizza类的实现
很好的解决了开放---闭合原则
package design.factory.gys.abstractfactory;
import design.factory.gys.Pizza.Pizza;
import design.factory.gys.factories.PizzaFactory;
public class OrderPizza {
private PizzaFactory factory;
public OrderPizza(PizzaFactory factory) {
super();
this.factory = factory;
}
public void setFactory(PizzaFactory factory) {
this.factory = factory;
}
public void start() {
Pizza pizza=factory.getPizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
pizza.finished();
}
}
下面看各个分店的营业状况:
// An highlighted block
package design.factory.gys.abstractfactory;
import design.factory.gys.factories.Londonfactory;
import design.factory.gys.factories.Newyorkfactory;
public class PizzaStore {
public static void main(String[] args) {
// TODO Auto-generated method stub
new OrderPizza(new Londonfactory()).start();
System.out.println("--------------------");
new OrderPizza(new Newyorkfactory()).start();
}
}
结果:
// An highlighted block
ThickPizza is preparing
ThickPizza is baking
ThickPizza is cutting
ThickPizza is boxing
ThickPizza has finished
--------------------
TakeandBakePizza is preparing
TakeandBakePizza is baking
TakeandBakePizza is cutting
TakeandBakePizza is boxing
TakeandBakePizza has finished
给嘉纹同学鼓掌,从此走向人生巅峰了。
五、工厂模式的比较
- 工厂方法模式与简单工厂模式在结构上的不同不是很明显。
- 工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
- 工厂方法模式之所以有一个别名叫多态性工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭”原则。而简单工厂模式在添加新产品对象后不得不修改工厂方法,扩展性不好。
工厂方法模式退化后可以演变成简单工厂模式。