简介
姓名:工厂方法
英文名:Factory method Pattern
价值观:扩展是我的专属
个人介绍:
Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses. (定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。)
(来自《设计模式之禅》)
你要的故事
还记得上一篇 单例模式 中的故事么?小明开着汽车去旅游、去学校、去聚会。这一次还是延续小明的故事,一个故事能讲 2 个设计模式,不容易呀。。。(每次想故事都想破脑袋,每一篇文章至少有 3 个故事从脑子里闪过,但最终留下的只有一个适合,为了就是能比较清晰简单的说明设计模式中的关键要点。)
简单工厂
小明家里以前不算很富裕,但是还是有一个不错的车库,什么汽车、摩托车、自行车啥的都放在这个车库里。小明每次要出去,都会到车库里面挑合适的车出发。比如,小明最近期末考试了,骑摩托车去学校考试,考完试之后,小明就准备去旅游,这次决定自驾游,开着自己家的小汽车去。这个场景我们用代码描述下。
public class SimpleFactoryTest {
public static void main(String[] args) {
XiaoMing xiaoMing = new XiaoMing();
// 小明骑摩托车去学校
IVehicle motorcycle = GarageFactory.getVehicle("motorcycle");
xiaoMing.goToSchool(motorcycle);
// 小明开汽车去旅游
IVehicle car = GarageFactory.getVehicle("car");
xiaoMing.travel(car);
}
}
/**
* 车库
*/
class GarageFactory {
public static IVehicle getVehicle(String type) {
if ("car".equals(type)) {
return new Car();
} else if ("motorcycle".equals(type)) {
return new Motorcycle();
}
throw new IllegalArgumentException("请输入车类型");
}
}
/**
* 交通工具
*/
interface IVehicle {
void run();
}
/**
* 汽车
*/
class Car implements IVehicle {
@Override
public void run() {
System.out.println("开汽车去。。。。");
}
}
/**
* 摩托车
*/
class Motorcycle implements IVehicle {
@Override
public void run() {
System.out.println("骑摩托车去。。。。");
}
}
class XiaoMing {
public void goToSchool(IVehicle vehicle) {
System.out.println("小明去学校");
vehicle.run();
}
public void travel(IVehicle vehicle) {
System.out.println("小明去旅游");
vehicle.run();
}
}
上面代码看懂了么? 小明家里有一个车库 GarageFactory,里面放着汽车 Car 和摩托车 Motorcycle,小明要出去的时候,就到车库选择车,通过传递参数给 GarageFactory.getVehicle(),指明要什么车,然后小明就骑着车出发了。
这个代码真正的术语叫:简单工厂模式(Simple Factory Pattern),也叫做静态工厂模式。它是工厂方法中的一个实现方式,从字面理解就可以知道,它是最简单的工厂方法实现方式。它有一点点小缺陷,就是扩展性不够好,在上面代码中,小明只能骑摩托车或者开汽车,如果小明要骑单车出去呢?势必得在 GarageFactory 中添加 if 是自行车的逻辑。这违反了哪条规则了?是不是那个允许扩展,拒绝修改的开闭原则?
不是说简单工厂这种实现方式不好,而是扩展性不够,在平时的开发中,简单工厂模式也用得不少。在这个小明家里车不多的情况下,用一个车库也是合适的。
工厂方法
小明老爸近几年赚了不少,车迷的两父子一直买车,家里的车越来越多,这时候,他们决定多建几个车库,按车类型放置。比如,有一个汽车库,一个摩托车库。这时候小明要开汽车就去汽车库,要骑摩托车就去摩托车库。代码实现如下。
public class FactoryMethodTest {
public static void main(String[] args) {
XiaoMing xiaoMing = new XiaoMing();
// 小明骑摩托车去学校
VehicleGarage motorcycleGarage = new MotorcycleGarage();
IVehicle motorcycle = motorcycleGarage.getVehicle();
xiaoMing.goToSchool(motorcycle);
// 小明开汽车去旅游
VehicleGarage carGarage = new CarGarage();
IVehicle car = carGarage.getVehicle();
xiaoMing.travel(car);
}
}
interface VehicleGarage {
IVehicle getVehicle();
}
/**
* 汽车车库
*/
class CarGarage implements VehicleGarage {
@Override
public IVehicle getVehicle() {
return new Car();
}
}
/**
* 摩托车车库
*/
class MotorcycleGarage implements VehicleGarage {
@Override
public IVehicle getVehicle() {
return new Motorcycle();
}
}
上面代码重用了简单工厂实现方式的交通接口以及摩托车和汽车的实现类。代码中有 2 个车库,一个是汽车车库 CarGarage,一个是摩托车库 MotorcycleGarage。如果小明要骑自行车,只需要建一个自行车车库,完全不用去修改汽车车库或者摩托车车库,就非常符合开闭原则,扩展性大大的提高。
总结
工厂方法模式可以说在你能想到的开源框架源码中必定会使用的一个设计模式,因为开源框架很重要一点就是要有扩展性,而工厂方法模式恰恰具有可扩展性。弄懂了工厂方法模式,以后看开源代码就很得心应手啦。
推荐阅读
单一职责原则(方法:修改名字还是密码?接口:洗碗、买菜还是倒垃圾?类:注册、登录和注销)
里氏替换原则(我儿来自新东方烹饪)
依赖倒置原则(抠门的饭店老板)
接口隔离原则(小伙子的作坊)
迪米特法则(手机上看电子书)
开闭原则(社保这点事)
创建型模式:单例模式(小明就只有 1 辆车)