工厂模式
案例
假设我开了一个工厂来组装特斯拉汽车,组装汽车需要“安装引擎-装上盖-装车门”这三道工序,目前这些工序都是由工人手工完成的,那么我写的代码可能如下
创建一个工人类,实现三道工序的操作:
public class Worker {
public void installEngine(Tesla tesla) {
// work work
}
public void installTopBox(Tesla tesla) {
// work work
}
public void installDoor(Tesla tesla) {
// work work
}
}
然后在主程序中创建工人实例,并执行这三个方法
public void installCar() {
Worker zhangSan = new Worker();
Tesla tesla01 = new Tesla();
zhangSan.installEngine(tesla01);
check(tesla01);
zhangSan.installTopBox(tesla01);
check(tesla01);
zhangSan.installDoor(tesla01);
check(tesla01);
}
public void check(Tesla tesla) {
// 检查汽车安装是否有问题
}
然后有一天,你引入了一个机器人,可以代替工人来进行汽车的组装操作。工人下岗了,那么你就需要在 installCar
方法中将和工人有关的相关代码全部删除,然后添加机器人的代码。
第二周,工人联合抗议,迫于舆论压力,你不得不放弃把工人全部裁光的想法,决定让人工组装与机器组装并行。于是你又需要将你才删掉的代码重新加回来。
在这一过程中,你频繁地修改 installCar
这个方法,极容易将这个方法改出问题,那么需要如何优化设计呢?
创建产品接口
在上面代码中,每做完一步就要进行一次检查操作,所以无论是人工操作还是机器操作,操作步骤都应该规范为这三步,不然检查代码可能就可能会出现问题。所以需要创建一个产品的接口来声明这些方法:
public interface Product {
void installEngine();
void installTopBox();
void installDoor();
}
让工人和机器人都来实现这个 Product 接口。
public void installCar() {
Product product = new Worker();
Tesla tesla01 = new Tesla();
product.installEngine(tesla01);
check(tesla01);
product.installTopBox(tesla01);
check(tesla01);
product.installDoor(tesla01);
check(tesla01);
}
虽说规范了这三道工序,但是仍不能保证工人和机器人能乖乖按照这个流程工作。比如工人又造反了,你又要给工人加一步“休息”的操作。所以最好把整个过程都封装到一个方法里面:
public void installCar() {
Product product = new Worker();
product.install();
}
创建工厂
安装的问题基本上解决了,接下来是初始化的问题。New 一个工人和 new 一个机器人的操作可能不同,首先构造函数传入的参数可能不同,然后比如说机器只有一个,只能使用单例模式;工人的数量有限,要从资源池里去获取等等。所以创建实例的操作最好也被隐藏。这个时候我们就使用工厂来专门负责创建的操作。这也是依赖倒置原则的体现:高层次
但这只是把创建代码换个地方放而已,并没有根本解决问题。所以我们把工厂弄成一个抽象类,具体的创建操作由各个子类去实现:
public abstract class ProductFactory {
public void install() {
Product product = createProduct();
product.installEngine();
product.installTopBox();
product.installDoor();
}
public abstract Product createProduct();
}
这里把核心业务逻辑 install()
放在抽象类里。如果出现特例,比如工人需要休息,就可以在工人的 Factory 中覆写 install()
方法,实现自己的逻辑。
在 installCar
方法中,调用对应的工厂方法即可:
public void installCar() {
ProductFactory factory = new WorkerFactory();
factory.install();
}
使用接口的默认方法实现工厂模式
import java.util.*;
interface Pet {}
class Dog implements Pet {}
class Cat implements Pet {}
interface Person {
Pet getPet();
default void play() {
System.out.println("playing with " + getPet());
}
}
class DogPerson implements Person {
private Dog dog = new Dog();
@Override
public Pet getPet() {
return dog;
}
}
class CatLover implements Person {
private Cat cat = new Cat();
@Override
public Pet getPet() {
return cat;
}
}
public class Sample {
public static void call(Person person) {
person.play();
}
public static void main(String[] args) {
call(new DogPerson());
call(new CatLover());
}
}