工厂模式绕不开的3种:简单工厂、工厂方法和抽象工厂,属于创建型模式,其中简单工厂不在GoF23种设计模式之列,但一并说了。
简单工厂模式
最近太热了,就用空调和冰箱来举例吧。
空调品牌非常多,如美的、长虹、格力、海尔等等,现在需要生产这些空调,由于生产过程非常复杂,对于客户端并不需要知道如何生产,只要拿到最终产品即可,于是就有了下面这段代码:
public class SimpleFactory {
public AirConditioner produce(String brand) {
switch (brand) {
case "Haier":
return new HaierAirConditioner();
case "Midea":
return new MideaAirConditioner();
default:
return null;
}
}
}
空调的接口:
public interface AirConditioner {
void print();
}
具体的空调产品:美的空调
public class MideaAirConditioner implements AirConditioner {
@Override
public void print() {
System.out.println("美的空调");
}
}
海尔空调:
public class HaierAirConditioner implements AirConditioner {
@Override
public void print() {
System.out.println("海尔空调");
}
}
下面是测试类:
public class SimpleFactoryTest {
public static void main(String[] args) {
//创建工厂
SimpleFactory simpleFactory = new SimpleFactory();
//生产美的空调
AirConditioner midea = simpleFactory.produce("Midea");
midea.print();
//生产海尔空调
AirConditioner haier = simpleFactory.produce("Haier");
haier.print();
}
}
//运行结果:
//美的空调
//海尔空调
以上就是简单工厂的实现,非常简单,可以把一些重复复杂的操作封装起来,让使用者不必关心产品是怎么生产的,只要知道想要什么就行(例如品牌作为参数传入),但从中我们也发现不少问题,例如现在需要增加一个品牌,比如格力空调,那么就需要去修改工厂类,这不符合开闭原则。
工厂方法模式工厂方法的核心就是让父类定义标准,由子类去实现具体要生产哪种商品。
还是上面空调的例子,这时我们需要定义一个空调工厂接口:
public interface IAirConditionerFactory {
AirConditioner produce();
}
现在需要生产海尔空调,就创建一个海尔空调的工厂:
public class HaierAirConditionerFactory implements IAirConditionerFactory {
@Override
public AirConditioner produce() {
return new HaierAirConditioner();
}
}
需要生产美的空调,就创建一个美的空调的工厂:
public class MideaAirConditionerFactory implements IAirConditionerFactory {
@Override
public AirConditioner produce() {
return new MideaAirConditioner();
}
}
下面是测试类:
public class FactoryMethodTest {
public static void main(String[] args) {
//创建海尔空调工厂
IAirConditionerFactory haierFactory = new HaierAirConditionerFactory();
//生产海尔空调
AirConditioner haier = haierFactory.produce();
haier.print();
//创建美的空调工厂
IAirConditionerFactory mideaFactory = new MideaAirConditionerFactory();
//生产美的空调
AirConditioner midea = mideaFactory.produce();
midea.print();
}
}
这种方式的好处显而易见,如果我还需要增加格力空调的生产,只需要增加一个格力空调工厂类和一个格力空调产品类即可,对原有代码没有任何影响,符合开闭原则。有优点自然也会有缺点,对于比较复杂的系统,这种方法可能会产生非常多的类,显得臃肿,后期不便于维护,有利有弊,看怎么取舍了。
抽象工厂模式先引入两个概念:产品族和产品等级结构。
产品族:同一个工厂生产的满足不同客户个性化需求的一组相关产品。如海尔生产的空调、冰箱。
产品等级结构:产品继承结构,如我们上面的海尔空调、美的空调就是空调的一个产品等级结构。
接下来,需要生产空调和冰箱,空调还是用上面的类,接下来创建冰箱的接口:
public interface Fridge {
void print();
}
海尔冰箱
public class HaierFridge implements Fridge {
@Override
public void print() {
System.out.println("海尔冰箱");
}
}
美的冰箱
public class MideaFridge implements Fridge {
@Override
public void print() {
System.out.println("美的冰箱");
}
}
工厂接口,定义生产空调和冰箱的方法
public interface IFactory {
AirConditioner produceAirConditioner();
Fridge produceFridge();
}
海尔工厂
public class HaierFactory implements IFactory {
@Override
public AirConditioner produceAirConditioner() {
return new HaierAirConditioner();
}
@Override
public Fridge produceFridge() {
return new HaierFridge();
}
}
美的工厂
public class MideaFactory implements IFactory {
@Override
public AirConditioner produceAirConditioner() {
return new MideaAirConditioner();
}
@Override
public Fridge produceFridge() {
return new MideaFridge();
}
}
下面是测试类:
public class AbstractFactoryTest {
public static void main(String[] args) {
//创建海尔工厂
IFactory haierFactory = new HaierFactory();
//生产海尔冰箱
Fridge haierFridge = haierFactory.produceFridge();
haierFridge.print();
//生产海尔空调
AirConditioner haierAirConditioner = haierFactory.produceAirConditioner();
haierAirConditioner.print();
//创建美的工厂
IFactory mideaFactory = new MideaFactory();
//生产美的空调
mideaFactory.produceAirConditioner().print();
//生产美的冰箱
mideaFactory.produceFridge().print();
}
}
好了,继续思考一下工厂方法那个扩展,现在需要生产格力空调和格力冰箱,我们只需要创建一个格力工厂,和相应的格力空调、格力冰箱类即可,也符合开闭原则,但这是在产品等级结构的扩展,完全没有问题,如果是产品族的扩展呢?那问题就大了,假设现在需要增加一个洗衣机,那怎么办,是不是就得修改IFactory了,而修改了IFactory,那么导致其他实现类都得修改,影响巨大。所以抽象工厂模式在产品族的扩展就不符合开闭原则了。
学到这里,我就有个疑问了,工厂方法和抽象工厂之间的区别是什么呢?下面就说说自己的理解:
1.简单工厂就只有一个工厂类,通过传入的参数决定生产哪种商品,有大量的if-else。
2.工厂方法可以有多个工厂,但只针对一种产品,父类定义标准,由子类决定具体生产哪种商品。
3.抽象工厂可以有多个工厂,多种产品,一个工厂可以生产多种产品。
具体使用场景:
1.有大量复杂的创建操作而不关心创建细节;
2.可扩展的内部组件



