工厂模式
前言
工厂模式是设计模式中对我困扰最多的一个设计模式。网上有很多博客在讲工厂模式有三种(简单工厂、工厂方法和抽象工厂),代码也很简单,但是我就一直搞不懂为什么要有个工厂方法模式,以及工厂方法模式在所谓的开闭原则下面相比简单工厂的优点。
现在大致明白了,为了解耦,接下来介绍各个工厂模式的实现以及优缺点。文中代码示例可以去github查看。
介绍
工厂模式分三类:
- 简单工厂模式:创建产品接口,具体产品实现该接口,工厂类对象负责根据参数生成不同类型的产品
- 工厂方法模式:对简单工厂中的工厂类进一步抽象为接口。
- 抽象工厂模式:相比工厂方法模式,多了个产品族的概念,工厂接口中有多个方法创建不同的产品。
个人认为工厂方法模式和抽象工厂模式都是抽象工厂模式。顾名思义,抽象工厂不就是把工厂类抽象成接口。只不过工厂方法是只能创建一个产品,抽象工厂可以创建多个产品。
简单工厂模式
简单工厂不算设计模式,应该算是一个代码优化,日常写代码的时候我们也会写出来类似的。总而言之,他是根据参数类型生成不同类型的产品的一个类。比如我们定义一个鼠标工厂,根据传入的参数决定生产哪种类型的鼠标:0生成联想,1生成戴尔,2生成罗技,罗技鼠标是真的好用。
简单工厂由抽象产品接口、具体产品类和产品工厂三部分组成。产品工厂负责根据传递参数制造不同的对象。
代码示例
/**
* 鼠标接口
*/
public interface Mouse {
String getName();
Integer getPrice();
default void print() {
System.out.println("鼠标名称:" + getName() + ",鼠标价格:" + getPrice());
}
}
/**
* 戴尔鼠标
*/
public class DellMouse implements Mouse {
@Override
public String getName() {
return "戴尔鼠标";
}
@Override
public Integer getPrice() {
return 50;
}
}
/**
* 惠普鼠标
*/
public class HpMouse implements Mouse {
@Override
public String getName() {
return "惠普鼠标";
}
@Override
public Integer getPrice() {
return 10;
}
}
/**
* 罗技鼠标
*/
public class LogiMouse implements Mouse {
@Override
public String getName() {
return "罗技鼠标";
}
@Override
public Integer getPrice() {
return 100;
}
}
/**
* 鼠标工厂类
*/
public class MouseFactory {
public static Mouse createMouse(Integer type) throws IllegalAccessException {
assert type != null;
switch (type) {
case 0:
return new HpMouse();
case 1:
return new DellMouse();
case 2:
return new LogiMouse();
default:
throw new IllegalAccessException("参数异常");
}
}
}
public void simpleFactoryTest() throws IllegalAccessException {
Mouse mouse = MouseFactory.createMouse(0);
mouse.print();
Mouse mouse1 = MouseFactory.createMouse(1);
mouse1.print();
Mouse mouse2 = MouseFactory.createMouse(2);
mouse2.print();
}
优缺点
优点:较另外两个工厂模式而言,代码简洁明了。工厂类对象提供了一个根据类型选择创建对象的方法。
缺点:工厂类对象耦合性高,破坏了开闭原则,当需要添加一个新产品时,工厂类对象要做修改。
工厂方法和抽象工厂模式
我们将工厂方法和抽象工厂合并到一块讲解,因为从代码结构上来看,他们两个是一样的,只不过抽象工厂方法工厂中有多个方法,可以创建多个产品。
工厂方法模式
简单工厂每次添加新产品的时候需要新增产品类,并且在工厂类中增加对应的代码逻辑。将简单工厂模式再次优化,对工厂类抽象成接口,具体工厂生产具体产品。新增产品时,只需要新增对应工厂,无需修改原有工厂代码。
简单工厂由抽象产品接口、具体产品类、抽象工厂接口和具体工厂组成,工厂和产品相对应。
代码示例
//抽象工厂接口
public interface Factory {
Mouse createMouse();
}
// 戴尔工厂类
import com.hello.designPattern.FactoryPattern.interfaces.Factory;
import com.hello.designPattern.FactoryPattern.interfaces.Mouse;
import com.hello.designPattern.FactoryPattern.model.DellMouse;
public class DellFactory implements Factory {
@Override
public Mouse createMouse() {
return new DellMouse();
}
}
// 惠普工厂类
public class HpFactory implements Factory {
@Override
public Mouse createMouse() {
return new HpMouse();
}
}
// 罗技工厂类
public class LogiFactory implements Factory {
@Override
public Mouse createMouse() {
return new LogiMouse();
}
}
// 测试方法
@Test
public void factoryMethodTest(){
Mouse hoMouse = new HpFactory().createMouse();
Mouse dellMouse = new DellFactory().createMouse();
Mouse logiMouse = new LogiFactory().createMouse();
hoMouse.print();
dellMouse.print();
logiMouse.print();
}
抽象工厂模式
接下来问题就来了,工厂不仅造鼠标,还造键盘,代码就需要在工厂接口中添加一个创建键盘的一个方法,这个时候,工厂方法模式就变成了抽象工厂模式。
抽象工厂模式代码就不在文中体现了,跟工厂方法模式基本上一样,添加了一个键盘接口,实现了惠普键盘、戴尔键盘和罗技键盘三个对象,然后在工厂类接口中添加创建键盘的方法,各工厂实现该方法。具体代码可见github
总结
在工作中,简单工厂适用于大部分业务逻辑不复杂的场景,代码少,类少,简单粗暴。如果需求较为复杂,并且时常变更,那就用工厂方法或抽象工厂。