本文将从以下三个方面讲解工厂模式:
- 简单工厂模式
- 工厂模式
- 抽象工厂模式
一、简单工厂模式
首先简单工厂就是定义一个工厂类,然后根据参数的不同去创建不同的实例,他们都拥有一个共同的父类。简单工厂是工厂模式最简单实用的模式。
先简单举个例子解释一下什么是简单工厂。每天我们都要做饭,米饭的做法有很多种,有炒饭、泡饭等等。一般情况下,我们会用一个对象去表示炒饭或者泡饭。
/**
* 米饭(炒饭)
*/
public class friedRice {
public void print() {
System.out.println("炒饭");
}
}
/**
* 米饭(泡饭)
*/
public class paofan {
public void print() {
System.out.println("泡饭");
}
}
但是现在不想吃炒饭了,决定以后变成吃蛋炒饭,但是原先的炒饭我又不能去废除。那就需要将上述的炒饭修改为蛋炒饭,但是原先已经有调用过炒饭的地方,我们都需要进行修改变成蛋炒饭,将一定增加我们修改代码的隐患与工作量。
当进行了简单工厂的封装之后,就变成了下面这样。
/**
* 米饭接口
*/
public interface IRice {
void print();
}
/**
* 米饭(炒饭)
*/
public class friedRice implements IRice {
@Override
public void print() {
System.out.println("一份炒饭")
}
}
/**
* 米饭(泡饭)
*/
public class paofan implements IRice {
@Override
public void print() {
System.out.println("一份泡饭");
}
}
我们有了一个公共的父类米饭。 然后子类继承父类实现具体的种类。
然后创建一个米饭工厂。
/**
* 创建米饭工厂
*/
public class RiceFactory {
public static IRice create(String type) {
switch (type) {
case "炒饭":
return new friedRice();
case "泡饭":
return new paofan();
default:
return new friedRice();
}
}
}
@Test
public void test() throws Exception {
//我要吃炒饭
IRice rice = RiceFactory.create("炒饭");
//我要吃泡饭
rice = RiceFactory.create("泡饭");
//吃什么由配置决定
rice = RiceFactory.create(xxxConfig.getRiceType());
}
这样我们只需要根据参数的不同去生产不同的饭,哪怕后续我要吃蛋炒饭,我只需要在工厂里将炒饭的地方 return new FriedRice(); 修改为 return new FriedRiceWithEggs();就行,不需要在调用的地方将实例修改为蛋炒饭。
当然不是所有的对象都要用简单工厂模式,需要有一定的要求性:最好具有多态性的对象,一般都会实现相同的接口,或者继承相同的基类。同时,创建工厂的参数不建议在代码种写死,可以从数据库中、枚举或者配置中读取字段获取参数。
二、工厂模式
在简单工厂中,可以创建在工厂里预设好的米饭。但是实际上一个工厂不能生产所有的东西,比如奥迪汽车厂只生产奥迪汽车,并不会去生产比亚迪汽车,因为这种情况,就要有专门的汽车厂去生产特定的汽车。工厂模式相当于更专业的简单工厂。同样举个例子解释:
我们先定义汽车基类和子类。
/**
* 汽车基类
*/
public abstract class BaseCar {
public abstract void Go();
}
/**
* 红旗汽车
*/
public class HongQiCar extends BaseCar {
@Override
public void Go() {
System.out.println("红旗汽车开始行驶了!");
}
}
/**
* 奥迪汽车
*/
public class AoDiCar extends BaseCar {
@Override
public void Go() {
System.out.println("奥迪汽车开始行驶了!");
}
}
然后需要一个汽车工厂和子类。
/**
* 汽车工厂基类
*/
public abstract class BaseFactory {
public abstract BaseCar CreateCar();
}
/**
* 红旗汽车工厂
*/
public class HongQiCarFactory extends BaseFactory {
@Override
public BaseCar CreateCar() {
return new HongQiCar();
}
}
/**
* 奥迪汽车工厂
*/
public class AoDiCarFactory extends BaseFactory {
@Override
public BaseCar CreateCar() {
return new AoDiCar();
}
}
然后我们再去生产汽车。
public void testCreateCar() {
//创建红旗汽车工厂对象。
BaseFactory hongQiCarFactory = new HongQiCarFactory();
//创建奥迪汽车工厂对象
BaseFactory aoDiCarFactory = new AoDiCarFactory();
//生产一辆红旗汽车
BaseCar hongQi = hongQiCarFactory.CreateCar();
hongQi.Go();
//生产一辆奥迪汽车
BaseCar aoDi = aoDiCarFactory.CreateCar();
aoDi.Go();
}
很容易理解,我们有一个公共的基类汽车厂,然后用汽车厂去定义专门品牌的汽车厂比如奥迪汽车厂、红旗汽车厂。当我们需要生产奥迪的时候,我们只需要创建一个奥迪的汽车厂去生产奥迪,需要红旗的时候,就用红旗汽车厂去生产红旗。对于用户来说,用户只能知道生产奥迪的奥迪汽车厂,以及生产红旗的红旗汽车厂,但是至于工厂是怎么创建的无需知道。哪怕后续用户需要增加一个生产奔驰的汽车厂,也只需要用汽车厂定义一个奔驰汽车厂,无需改动已有的汽车厂类。减少修改到其他代码的隐患,很好的符合了开闭原则。
三、抽象工厂模式
在系统中经常会遇到面临一系列相互依赖的对象需要创建,抽象工厂就是解决创建一系列相互依赖的对象。同样使用一个房屋风格创建的例子解释。
首先房屋由很多部分构成,比如屋顶,地板,窗户,房门等,我们需要这些的创建的基类(没有风格限制)。
/**
* 屋顶基类
**/
public abstract class BaseRoof {
public abstract void Create();
}
/**
* 地板基类
**/
public abstract class BaseFloor {
public abstract void Create();
}
/**
* 窗户基类
**/
public abstract class BaseWindow {
public abstract void Create();
}
/**
* 房门基类
**/
public abstract class BaseDoor {
public abstract void Create();
}
然后,我们定义出两种风格的房屋部分去实现基类。
/**
* 地板(欧式)
*/
public class EuropeanFloor extends BaseFloor {
@Override
public void Create() {
System.out.println("创建欧式的地板");
}
}
/**
* 屋顶(欧式)
*/
public class EuropeanRoof extends BaseRoof {
@Override
public void Create() {
System.out.println("创建欧式的房顶");
}
}
/**
* 窗户(欧式)
*/
public class EuropeanWindow extends BaseWindow {
@Override
public void Create() {
System.out.println("创建欧式的窗户");
}
}
/**
* 房门(欧式)
*/
public class EuropeanDoor extends BaseDoor {
@Override
public void Create() {
System.out.println("创建欧式的房门");
}
}
/**
* 地板(中式)
*/
public class ChineseFloor extends BaseFloor {
@Override
public void Create() {
System.out.println("创建中式的地板");
}
}
/**
* 屋顶(中式)
*/
public class ChineseRoof extends BaseRoof {
@Override
public void Create() {
System.out.println("创建中式的房顶");
}
}
/**
* 窗户(中式)
*/
public class ChineseWindow extends BaseWindow {
@Override
public void Create() {
System.out.println("创建中式的窗户");
}
}
/**
* 房门(中式)
*/
public class ChineseDoor extends BaseDoor {
@Override
public void Create() {
System.out.println("创建中式的房门");
}
}
这样就有了两种不同风格的装修。然后我们需要一个创建无风格房子的工厂基类。
/**
* 抽象工厂基类
*/
public abstract class BaseFactory {
/**
* 创建房顶
*/
public abstract BaseRoof CreateRoof();
/**
* 创建地板
*/
public abstract BaseFloor CreateFloor();
/**
* 创建窗户
*/
public abstract BaseWindow CreateWindow();
/**
* 创建房门
*/
public abstract BaseDoor CreateDoor();
}
再创建两种不同风格的房屋子类继承实现基类。
/**
* 创建对象工厂(欧式)
*/
public class EuropeanFactory extends BaseFactory {
/**
* 创建房顶(欧式)
*/
@Override
public BaseRoof CreateRoof() {
return new EuropeanRoof();
}
/**
* 创建地板(欧式)
*/
@Override
public BaseFloor CreateFloor() {
return new EuropeanFloor();
}
/**
* 创建窗户(欧式)
*/
@Override
public BaseWindow CreateWindow() {
return new EuropeanWindow();
}
/**
* 创建房门(欧式)
*/
@Override
public BaseDoor CreateDoor() {
return new EuropeanDoor();
}
}
/**
* 创建对象工厂(中式)
*/
public class ChineseFactory extends BaseFactory {
/**
* 创建房顶(中式)
*/
@Override
public BaseRoof CreateRoof() {
return new ChineseRoof();
}
/**
* 创建地板(中式)
*/
@Override
public BaseFloor CreateFloor() {
return new ChineseFloor();
}
/**
* 创建窗户(中式)
*/
@Override
public BaseWindow CreateWindow() {
return new ChineseWindow();
}
/**
* 创建房门(中式)
*/
@Override
public BaseDoor CreateDoor() {
return new ChineseDoor();
}
}
工厂准备好了,我们如何去调用工厂生产出我们需要的风格类型呢,我们只需要根据需要去创建出指定风格的工厂,然后使用这个工厂里的方法就可以创建出这种风格的房子。
public void testCreateCar() {
//创建房子工厂(欧式)
BaseFactory europeanFactory = new EuropeanFactory();
europeanFactory.CreateRoof().Create();
europeanFactory.CreateFloor().Create();
europeanFactory.CreateWindow().Create();
europeanFactory.CreateDoor().Create();
// 创建房子工厂(中式)
BaseFactory chineseFactory = new ChineseFactory();
chineseFactory.CreateRoof().Create();
chineseFactory.CreateFloor().Create();
chineseFactory.CreateWindow().Create();
chineseFactory.CreateDoor().Create();
}
后续我如果需要增加其他风格的房子,我也只需要增加一个房屋工厂去继承基类实现另一个风格。
最后,欢迎大家评论区批评指教~