工厂模式
简单工厂模式
定义一个工厂类,根据传入参数的值返回不同的实例。
如上图,我们实现一个简单鼠标工厂类,根据我们传入的参数生成不同品牌的鼠标,每种鼠标都实现了鼠标这一接口。
代码实现
鼠标接口及其实现类
public interface Mouse {
void sayHi();
}
public class DellMouse implements Mouse {
@Override
public void sayHi() {
System.out.println("我是戴尔鼠标");
}
}
public class HpMouse implements Mouse {
@Override
@TestAnnotation
public void sayHi() {
System.out.println("我是惠普鼠标");
}
}
工厂类
public class MouseFactory {
public static Mouse createMouse(int type){
switch (type) {
case 0: return new DellMouse();
case 1: return new HpMouse();
case 2: return new LenovoMouse();
default: return new DellMouse();
}
}
}
使用工厂创建鼠标
public static void main(String[] args) {
Mouse mouse = MouseFactory.createMouse(1);
mouse.sayHi();
}
优缺点
特点:
- 被创建的实例拥有共同的父类或接口。
适用场景:
- 需要创建的对象较少
- 客户端不关心对象的创建过程
优缺点:
- 优点:隐藏对象创建细节
- 缺点:如果创建对象的创建过程复杂或者创建对象种类多会导致工厂类代码臃肿,比如我们上面的例子中的鼠标工厂如果要创建几十种鼠标的话判断代码就会很长。
- 缺点:新增、删除子类违反开闭原则,因为我们要对工厂类的相关代码做增删。
工厂方法模式
为了解决简单工厂模式中的一些问题,引入工厂方法模式,定义一个创建对象的接口,让子类决定实例化哪个类。
代码实现
鼠标接口和实现类与简单工厂模式相同,这里就略过了。
定义鼠标工厂接口,声明创建鼠标对象方法
public interface MouseFactory {
Mouse createMouse();
}
分别实现不同鼠标的工厂实现类
public class DellMouseFactory implements MouseFactory {
@Override
public Mouse createMouse() {
return new DellMouse();
}
}
public class HpMouseFactory implements MouseFactory {
@Override
public Mouse createMouse() {
return new HpMouse();
}
}
使用对应鼠标工厂创建鼠标
public static void main(String[] args) {
MouseFactory mf = new HpMouseFactory();
Mouse mouse = mf.createMouse();
mouse.sayHi();
}
优缺点
特点:对类的实例化延迟到其子类
- 优点:使用工厂方法模式后,新增或删除一个鼠标实现类,不需要修改工厂代码而是增加对应的工厂类。
- 优点:遵循单一职责原则,每个工厂类只负责对应类的实例化
工厂方法模式有两个严重的缺点
- 缺点:添加子类的时候要添加对应的工厂类,随着业务发展,类的数量会变得臃肿。
- 缺点:只支持同一类产品的创建,比如只能创建各种鼠标,不能创建键盘等其他产品。
抽象工厂模式
为了解决工厂方法模式不支持多种类的创建,接着引入抽象工厂模式。
抽象工厂模式提供了一个创建一系列相关或相互依赖的接口,如下图所示的PcFactory
既可以创建鼠标类Mouse
又可以创建键盘类Keybo
,为不同厂商提供不同的PcFactory
实现类来配套对应的键盘鼠标。
代码实现
鼠标接口及其实现类与简单工厂模式下相同,这里略过
键盘接口及其实现类
public interface Keyboard {
void sayHello();
}
public class DellKeyboard implements Keyboard {
@Override
public void sayHello() {
System.out.println("我是戴尔键盘");
}
}
public class HpKeyboard implements Keyboard {
@Override
public void sayHello() {
System.out.println("我是惠普键盘");
}
}
定义一个生产电脑相关物件的工厂接口
public interface ComputerFactory {
Mouse createMouse();
Keyboard createKeyboard();
}
为不同厂商实现接口
public class DellComputerFactory implements ComputerFactory {
@Override
public Mouse createMouse() {
return new DellMouse();
}
@Override
public Keyboard createKeyboard() {
return new DellKeyboard();
}
}
public class HpComputerFactory implements ComputerFactory {
@Override
public Mouse createMouse() {
return new HpMouse();
}
@Override
public Keyboard createKeyboard() {
return new HpKeyboard();
}
}
生产键盘鼠标
public static void main(String[] args) {
ComputerFactory cf = new HpComputerFactory();
Mouse mouse = cf.createMouse();
Keyboard keyboard = cf.createKeyboard();
mouse.sayHi();
keyboard.sayHello();
}
优缺点
- 优点:抽象工厂模式解决了工厂模式只支持生产一种产品的缺点
- 优点:新增删除产品簇满足开闭原则和单一职责原则,如新增一个新的产商
- 缺点:新增删除产品簇中的某个产品依旧违反开闭原则,例如新增一个耳机,就要修改所有工厂实现类。
总结
工厂模式主要分为简单工厂模式、工厂方法模式和抽象工厂模式。
- 简单工厂模式提供了一个统一的工厂,通过传入参数来生成对应的实例。
- 工厂方法模式通过为不同的类实现不同工厂,遵循开闭原则。
- 抽象工厂模式提供了为一组相互关联的类实例化的工厂,解决了工厂方法模式不支持多种类的创建问题。
扩展思考
- Spring 框架中的 IOC 容器是如何使用工厂模式的(工厂模式 + 反射)
- 抽象工厂模式在引入新类时依然不遵循开闭原则,该如何解决,考虑加入反射。