第四章:工厂模式
一、简单工厂模式
简单工厂模式属于创建型模式,是工厂模式家族中最简单实用的模式
来看一下没有工厂之前的代码
Pizza 类
public abstract class Pizza {
public abstract void prepare();
public abstract void bake();
public abstract void cut();
public void box() {
System.out.println("披萨正在装盒");
}
}
Pizza 的具体子类
public class NanjingPizza extends Pizza {
private String name = "南京披萨";
public String getName() {
return name;
}
@Override
public void prepare() {
System.out.println("为" + name + "准备原材料");
}
@Override
public void bake() {
System.out.println("正在烘培" + name);
}
@Override
public void cut() {
System.out.println("将" + name + "切成小份");
}
@Override
public String toString() {
return name;
}
}
public class SuzhouPizza extends Pizza {
private String name = "苏州披萨";
public String getName() {
return name;
}
@Override
public void prepare() {
System.out.println("为" + name + "准备原材料");
}
@Override
public void bake() {
System.out.println("正在烘培" + name);
}
@Override
public void cut() {
System.out.println("将" + name + "切成小份");
}
@Override
public String toString() {
return name;
}
}
PizzaOrder 类
public class PizzaOrder {
public void orderPizza() {
System.out.println("披萨店营业啦!!!(输入打样来打烊)");
while (true) {
String type = getType();
if (type.equals("打烊")) {
break;
}
Pizza pizza = makePizza(type);
System.out.println("请拿好您的" + pizza);
}
}
public Pizza makePizza(String type) {
Pizza pizza = null;
switch (type) {
case "南京披萨":
pizza = new NanjingPizza();
break;
case "苏州披萨":
pizza = new SuzhouPizza();
break;
default:
System.out.println("目前不提供这种披萨");
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
public String getType() {
System.out.println("请输入披萨种类:");
Scanner scanner = new Scanner(System.in);
return scanner.next();
}
}
这里发现我们将生产 Pizza 对象的代码放到了我们的一个具体的业务中,构造一个相应 Pizza 对象还是挺多步骤的。而且如果新加一种 Pizza,我们就要改业务里的代码,这不符合 OCP。
所以我们将生产 Pizza 的过程专门用个类封装起来,这样代码既能重用,修改时也只用修改一处
SimpleFactory 类
public class SimpleFactory {
public Pizza makePizza(String type) {
Pizza pizza = null;
switch (type) {
case "南京披萨":
pizza = new NanjingPizza();
break;
case "苏州披萨":
pizza = new SuzhouPizza();
break;
default:
System.out.println("目前不提供这种披萨");
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
PizzaOrder 类
public class PizzaOrder {
private SimpleFactory factory;
public PizzaOrder() {
factory = new SimpleFactory();
}
public void orderPizza() {
System.out.println("披萨店营业啦!!!(输入打样来打烊)");
while (true) {
String type = getType();
if (type.equals("打烊")) {
break;
}
Pizza pizza = factory.makePizza(type);
System.out.println("请拿好您的" + pizza);
}
}
public String getType() {
System.out.println("请输入披萨种类:");
Scanner scanner = new Scanner(System.in);
return scanner.next();
}
}
二、工厂方法模式
之前我们生产的是南京披萨和苏州披萨,现在问题升级,需要生产超大杯南京披萨、大杯南京披萨、超大杯苏州披萨、大杯苏州披萨四种披萨。为了解决问题,creatPIzza 的判断逻辑里又要增加两个 if 语句( ̄m ̄)。但是。。。不难发现这里的所有披萨大致分为两种 Pizza,超大杯和大杯,所以我打算使用工厂方法模式解决问题,就不用写那么多 if 语句啦!
Pizza 类及其子类省略
Factory 类
public abstract class Factory {
public abstract Pizza makePizza(String type);
}
BigFactory 类
public class BigFactory extends Factory{
@Override
public Pizza makePizza(String type) {
Pizza pizza = null;
switch (type) {
case "南京披萨":
pizza = new BigNanjingPizza();
break;
case "苏州披萨":
pizza = new BigSuzhouPizza();
break;
default:
System.out.println("目前不提供这种披萨");
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
SuperBigFactory 类
public class SuperBigFactory extends Factory{
@Override
public Pizza makePizza(String type) {
Pizza pizza = null;
switch (type) {
case "南京披萨":
pizza = new SuperBigNanjingPizza();
break;
case "苏州披萨":
pizza = new SuperBigSuzhouPizza();
break;
default:
System.out.println("目前不提供这种披萨");
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
BigPizzaOrder 类
public class BigPizzaOrder {
private Factory factory;
public BigPizzaOrder() {
factory = new BigFactory();
}
public void orderPizza() {
System.out.println("披萨店营业啦!!!(输入打样来打烊)");
while (true) {
String type = getType();
if (type.equals("打烊")) {
break;
}
Pizza pizza = factory.makePizza(type);
System.out.println("请拿好您的" + pizza);
}
}
public String getType() {
System.out.println("请输入披萨种类:");
Scanner scanner = new Scanner(System.in);
return scanner.next();
}
}
SuperBigPizza 类
public class SuperBigPizzaOrder {
private Factory factory;
public SuperBigPizzaOrder() {
factory = new SuperBigFactory();
}
public void orderPizza() {
System.out.println("披萨店营业啦!!!(输入打样来打烊)");
while (true) {
String type = getType();
if (type.equals("打烊")) {
break;
}
Pizza pizza = factory.makePizza(type);
System.out.println("请拿好您的" + pizza);
}
}
public String getType() {
System.out.println("请输入披萨种类:");
Scanner scanner = new Scanner(System.in);
return scanner.next();
}
}
可以看到工厂方法模式将创建的方法放到一个抽象类中,具体实现由其子类决定。
这时如果我们新增一个小杯南京披萨和小杯苏州披萨只需再新建一个小杯工厂就行了,之前的代码都不用动
工厂方法模式就是将众多的子类对象根据特征分成几类对象,然后对这几类对象分别对应相应的工厂,由之前的一个简单工厂变成了现在的很多个工厂。
不过问题也显然而见,如果子类对象们的分类有很多,那就必须创建很多工厂。
三、抽象工厂模式
工厂方法会导致工厂类太多的问题,为了削减工厂类,我们需要抽象工厂模式
披萨再怎么种类繁多,也就只有超大杯披萨、大杯披萨、中杯披萨,所以我们可以在一个工厂类中写多个创建方法
Factory 类
public abstract class Factory {
public abstract Pizza makeSuperPizza(String type);
public abstract Pizza makeBigPizza(String type);
public abstract Pizza makemedianPizza(String type);
}
SuperFactory 类
public class SuperFactory extends Factory {
@Override
public Pizza makeSuperPizza(String type) {
Pizza pizza = null;
switch (type) {
case "南京披萨":
pizza = new SuperBigNanjingPizza();
break;
case "苏州披萨":
pizza = new SuperBigSuzhouPizza();
break;
default:
System.out.println("目前不提供这种披萨");
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
@Override
public Pizza makeBigPizza(String type) {
Pizza pizza = null;
switch (type) {
case "南京披萨":
pizza = new BigNanjingPizza();
break;
case "苏州披萨":
pizza = new BigSuzhouPizza();
break;
default:
System.out.println("目前不提供这种披萨");
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
@Override
public Pizza makemedianPizza(String type) {
Pizza pizza = null;
switch (type) {
case "南京披萨":
pizza = new MedianNanjingPizza();
break;
case "苏州披萨":
pizza = new MedianSuzhoPizza();
break;
default:
System.out.println("目前不提供这种披萨");
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
这样工厂类就大大缩减了,不过抽象工厂和工厂方法没有谁就一定更好,所以看情况使用