在程序猿世界里,能够写出优雅、可扩展、低耦合、甚至像诗一样的代码,是每个程序猿毕生的追求~
秉承这个人生的终极理想,猿小二入职一家新公司,开始慢慢熟悉公司的代码,越来越觉得不对劲,这家公司的代码写的可真烂,各种耦合牵一发动全身,完全不是面试时老板说的公司的代码都像诗一样优雅,猿小二感觉自己上当了!
没办法,猿小二只能硬着头皮继续了,不过猿小二转念一想,代码这么多问题,不就是给我表现的机会吗?猿小二心中窃喜,思考着如何用设计模式来重构现在的代码,增加程序间的可扩展性并降低程序间的耦合度,猿小二想到最近正在研究的工厂模式,于是猿小二开始了他的改造之旅......
![f0b78cbeb6711e1351ebdcca224ad0eb.png](https://i-blog.csdnimg.cn/blog_migrate/614c97dc49c89a401f593ecfb74931e2.jpeg)
经过了一段时间的努力,猿小二终于完成了一部分代码的改造;正当他在对自己的成就自信满满的时候,一些同事突然过来说改造之后的代码虽然感觉很优雅(不明觉厉),但是他们却看不懂,猿小二说,我来给大家讲一下我的改造之旅吧,其实也不是那么顺利的,于是猿小二又开始了他的分享之旅~~~
简单工厂模式(静态工厂模式)
最开始的时候,猿小二对一些代码的改造使用了简单工厂模式,简单工厂就是有一个工厂类,根据传入的参数不同创建不同的对象实例;比如说,有个生产汽车的工厂(CarFactory),可以生产各种不同品牌的汽车(AudiCar、BWMCar、AMGCar)
![882d33aa98f2054e6df53490df8b16aa.png](https://i-blog.csdnimg.cn/blog_migrate/6665361928094e120d97cf2b9014492e.jpeg)
定义一个汽车的接口
/**
* 汽车接口
*/
public interface Car {
// 汽车会跑
public void run();
}
定义各种品牌的汽车类,实现汽车接口
/**
* 奥迪汽车类
*/
public class AudiCar implements Car {
public void run() {
System.out.println("奥迪汽车...");
}}
/**
* 宝马汽车类
*/
public class BWMCar implements Car {
public void run() {
System.out.println("宝马汽车...");
}
}
对于这些不同品牌的汽车我们就可以提供一个工厂类,来根据不同的品牌参数去生产不同的汽车
/**
* 汽车工厂
*/
public class CarFactory {
// 生产不同品牌的汽车
public Car produce(String bank) {
if ("AudiCar".equals(bank)) {
return new AudiCar();
} else if ("BWMCar".equals(bank)) {
return new BWMCar();
}
return null;
}
}
有了工厂对象了,接下来就可以生产汽车了
/**
* 测试生产汽车
*/
public class CarTest {
public static void main(String[] args) {
// 创建汽车工厂
CarFactory carFactory = new CarFactory();
// 生产奥迪汽车
Car audi = carFactory.produce("Audi");
audi.run();
// 生产宝马汽车
Car bwm = carFactory.produce("BWM");
bwm.run();
}
}
这样以来的话,我们就可以不用关心具体汽车对象的生产过程,只需要根据传递的参数(汽车品牌)就可以创建需要的汽车品牌了。
不过还有一个问题,就是如果我们要生产其他品牌的汽车,比如:丰田汽车,就的去改工厂类CarFactory里代码,如果是汽车品牌多了话,岂不是要经常修改,这种频繁修改的代码的行为,这显然不符合开放-封闭原则,对于追求极致的猿小二来说,显然是接受不了的,于是他有开始新一轮的改造。
工厂方法模式
这个时候,猿小二想到了工厂方法模式,不同于简单工厂模式的是,工厂方法模式没有使用统一的工厂去生产不同的汽车品牌,而是分别给不同的汽车品牌建设不同工厂,比如:要生产Audi汽车,就创建Audi的汽车工厂;这样每一个汽车品牌都有自己独立的汽车生产工厂。
![61855004fa0c30c6bf107f47f4762db9.png](https://i-blog.csdnimg.cn/blog_migrate/f4ba1387fd49cf3fc77147d40802e229.jpeg)
首先,先抽取一个最顶层的汽车工厂接口
/**
* 汽车工厂
*/
public interface CarFactory {
// 生产汽车
public Car produce();
}
然后,让不同的汽车品牌工厂都实现这个接口,比如:奥迪汽车工厂、宝马汽车工厂、丰田汽车工厂。
/**
* 奥迪汽车工厂
*/
public class AudiCarFactory implements CarFactory {
// 负责生产奥迪汽车
public Car produce() {
return new AudiCar();
}
}
丰田汽车工厂
/**
* 丰田汽车厂
*/
public class TOYOTACarFactory implements CarFactory {
// 负责生产丰田汽车
public Car produce() {
return new TOYOTACar();
}
}
测试生产汽车
/**
* 汽车工厂方法测试
*/
public class CarFactoryMethodTest {
public static void main(String[] args) {
// 奥迪汽车厂生产奥迪汽车
CarFactory audiCarFactory = new AudiCarFactory();
Car audi = audiCarFactory.produce();
audi.run();
// 宝马汽车厂生产宝马汽车
CarFactory toyotaCarFactory = new TOYOTACarFactory();
Car toyota = toyotaCarFactory.produce();
toyota.run();
}
}
通过这种工厂方法模式,我们再也不用担心增加汽车品牌而去修改汽车工厂的代码了,只需要创建相应品牌的汽车工厂类就可以了,而且这种方式还符合了设计模式的开放-封闭原则,简直是完美;虽然有可能随着汽车品牌的增加,工厂类也不断增加,一定程度上会增加系统的复杂度,但是相对于它带来的好处还是可以接受的。
本来事情已经告一段落,猿小二可以稍微轻松下了,没想到老板说又有新的需求了,这些汽车厂要涉足汽车发动机领域,想要自己生产汽车发动机,这可难坏了猿小二,本来按照原来的思路,可以在创建发动机的工厂类,但是考虑到制造成本(发动机和组装在同一个工厂生产),准备对原来的汽车工厂进行改造。
抽象工厂模式
为了满足新的需求,需要在对原来的工厂进行改造,增加生产发动机的方法,这种方式就涉及到另外一种抽象工厂模式,在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法用于产生多种不同类型的对象,比如,汽车工厂既生产汽车,也生产汽车发动机,于是猿小二开始新一轮的改造。
![53cd104b189bcfd396b2a015119d7f6b.png](https://i-blog.csdnimg.cn/blog_migrate/6e5048e3d70ec855e7f6d14c315a9895.jpeg)
首先,我们先定义抽象工厂类,它既可以生产汽车,也可以生产汽车发动机
/**
* 抽象工厂
*/
public interface CarAbstractFactory {
// 生产汽车
public Car produce();
// 生产发动机
public Engine createEngine();
}
奥迪汽车工厂类实现这个抽象接口,生产奥迪汽车和奥迪的发动机
/**
* 奥迪汽车工厂
*/
public class AudiCarFactory implements CarAbstractFactory {
// 负责生产奥迪汽车
public Car produce() {
return new AudiCar();
}
// 生产奥迪发动机
public Engine create() {
return new AudiEngie();
}
}
这样我们就可以看到奥迪汽车厂就可以生产自己品牌的汽车和发动机,其他品牌也可以生产各自的汽车和发动机
/**
* 抽象工厂测试
*/
public class AbstractFactoryTest {
public static void main(String[] args) {
// 奥迪汽车厂
CarAbstractFactory audiCarFactory = new AudiCarFactory();
// 生产奥迪汽车
Car produce = audiCarFactory.produce();
produce.run();
// 生产奥迪汽车发动机
Engine audiengine = audiCarFactory.createEngine();
audiengine.createEngine();
}
}
从这里我们可以看出其实抽象工厂模式是一个工厂可以生产多个产品类,也就是一系列相互关联的产品,比如:汽车和发动机。
其实,无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,虽然在形式有些区别,但是最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为通常情况下是结合使用;经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式;所以,在使用工厂模式时,只需要关心是不是达到我们的业务需求,并且最大限度降低系统间的耦合度。