目录
工厂模式
作用:实现了创建者和调用者的分离,帮助我们实例化对象。
核心本质:用工厂代替new操作实例化对象
将选择实现类,创建对象统一管理和控制,从而将调用者跟我们的实现类解耦
工厂模式是一种典型的解耦模式
满足的OOP七大原则:
开闭原则
依赖倒转原则
迪米特法则(要权衡好)
分类:
简单工厂模式:用来生成同一等级结构中的任意产品(对于增加的新的产品,需要扩展已有代码)。
工厂方法模式:用来生成同一等级结构中的固定产品(支持增加任意产品)。
抽象工厂模式:围绕一个超级工厂创建其他工厂。
适用场景:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。
实际上,创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。
创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。
简单工厂模式(静态工厂模式)Simple Factory
就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
简单工厂模式中的角色有:工厂,产品,客户端。看下例:
首先我们可以看一下类图
具体实现代码如下:
创建一个Car接口
public interface Car {
public void name();
}
编写两个实现类
public class WuLing implements Car{
@Override
public void name() {
System.out.println("五菱宏光");
}
}
public class Tesla implements Car{
@Override
public void name() {
System.out.println("特斯拉");
}
}
创建工厂类
public class CarFactory{
public static Car getCar(String car) {
if(car.equals("五菱")) {
return new WuLing();
}else if(car.equals("特斯拉")) {
return new Tesla();
}else {
return null;
}
}
}
测试一下
public class Comsumer {
public static void main(String[] args){
Car car1 = CarFactory.getCar("五菱");
Car car2 = CarFactory.getCar("特斯拉");
car1.name();
car2.name();
}
}
输出的结果:
我无需再去关心车是怎么来的,我只需要提供一个名称,从工厂里面拿就行了。
我们能很清楚的感受到这个模式的弊端,如果我们现在想要新增一个Car接口的实现类,添加一个大众的车,就必须要去修改工厂中的getCar()方法,违背了开闭原则。
当然,我们可以修改工厂类中的方法,需要什么就获取什么,无需我们再去输入参数
public class CarFactory{
public static Car getWuLing(){
return new WuLing();
}
public static Car getTesla(){
return new Tesla();
}
}
其实这也是不满足我们的需求的,我们仍旧需要去修改代码,只是说不会像上一个方法要去代码逻辑中去修改。
简单工厂模式存在的问题:
违背了开闭原则
违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中
工厂方法模式Factory Method
工厂方法模式是对简单工厂模式进一步的解耦,这相当于是把原本会因为业务代码而庞大的简单工厂类,拆分成了一个个的工厂类,这样代码就不会都耦合在同一个类里了。
工厂方法模式和简单工厂模式虽然都是通过工厂来创建对象,他们之间最大的不同是——工厂方法模式在设计上完全完全符合“开闭原则”。
直接看例子:
具体代码实现如下:
Car接口、Tesla类和WuLing类不变
创建车工厂接口
public interface CarFactory{
public Car getCar();
}
创建车工厂接口的实现类TeslaFactory工厂类和WuLingFactory类
public class TeslaFactory implements CarFactory{
@Override
public Car getCar(){
return new Tesla();
}
}
public class WuLingFactory implements CarFactory{
@Override
public Car getCar(){
return new WuLing();
}
}
最后测试一下
public class Comsumer {
public static void main(String[] args){
Car car1 = new WuLingFactory.getCar();
Car car2 = new TeslaFactory.getCar();
car1.name();
car2.name();
}
}
由于这里举的例子没有涉及到参数问题,所以我们的感觉不是很明显,试想一下,如果Tesla类或者WuLing类中有很多参数呢?这个方法对消费者来说就是友好的,我们无需去管车是怎么造的,它对应的工厂方法会去实例化它,我们只需要去调用工厂中的方法就可以了。
这里我认为狂神的流程图可能会更加清晰(加层)
在以下情况下可以使用工厂方法模式:
一个类不知道它所需要的对象的类。
一个类通过其子类来指定创建哪个对象
优点:
一个调用者想创建一个对象,只要知道其名称就可以了。
扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
抽象工厂模式Abstract Factory
抽象工厂模式相对工厂方法模式来讲,就是工厂方法模式是针对一个产品系列,而抽象工厂模式是针对多个产品系列的。
定义︰抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类。抽象工厂模式是工厂的工厂
我个人认为就是再加一层的意思,当然,这只是我个人的观点。
在讲案例之前,我们需要知道产品族和产品等级两个概念:
现在我们来看具体案例:
首先创建手机接口和路由器接口
//手机产品接口
public interface IPhoneProduct {
void start();
void shutdown();
void callup();
void sendSMS();
}
//路由器产品接口
public interface IRouterProduct {
void start();
void shutdown();
void openWifi();
void setting();
}
然后创建两个手机接口的实现类:小米手机和华为手机
//小米手机
public class XiaoMiPhone implements IPhoneProduct{
@Override
public void start() {
System.out.println("开启小米手机");
}
@Override
public void shutdown() {
System.out.println("关闭小米手机");
}
@Override
public void callup() {
System.out.println("小米手机打电话");
}
@Override
public void sendSMS() {
System.out.println("小米手机发短信");
}
}
//华为手机
public class HuaWeiPhone implements IPhoneProduct{
@Override
public void start() {
System.out.println("开启华为手机");
}
@Override
public void shutdown() {
System.out.println("关闭华为手机");
}
@Override
public void callup() {
System.out.println("华为手机打电话");
}
@Override
public void sendSMS() {
System.out.println("华为手机发短信");
}
}
创建两个路由器接口的实现类:小米路由器和华为路由器
//小米路由器
public class XiaoMiRouter implements IRouterProduct {
@Override
public void start() {
System.out.println("启动小米路由器");
}
@Override
public void shutdown() {
System.out.println("关闭小米路由器");
}
@Override
public void openWifi() {
System.out.println("小米路由器打开WiFi");
}
@Override
public void setting() {
System.out.println("小米路由器设置");
}
}
//华为路由器
public class HuaWeiRouter implements IRouterProduct {
@Override
public void start() {
System.out.println("启动华为路由器");
}
@Override
public void shutdown() {
System.out.println("关闭华为路由器");
}
@Override
public void openWifi() {
System.out.println("华为路由器打开WiFi");
}
@Override
public void setting() {
System.out.println("华为路由器设置");
}
}
编写一个抽象产品工厂来制造
//抽象产品工厂
public interface IProductFactory {
//生产手机
IPhoneProduct iphoneProduct();
//生产路由器
IRouterProduct irouterProduct();
}
创建抽象产品工厂的实现类
//小米工厂
public class XiaoMiFactory implements IProductFactory {
@Override
public IPhoneProduct iphoneProduct() {
return new XiaoMiPhone();
}
@Override
public IRouterProduct irouterProduct() {
return new XiaoMiRouter();
}
}
//华为工厂
public class HuaWeiFactory implements IProductFactory {
@Override
public IPhoneProduct iphoneProduct() {
return new HuaWeiPhone();
}
@Override
public IRouterProduct irouterProduct() {
return new HuaWeiRouter();
}
}
编写客户端测试:
public class Client {
public static void main(String[] args) {
System.out.println("**********华为系列***********");
//华为工厂
HuaWeiFactory huaweiFactory = new HuaWeiFactory();
IPhoneProduct huaweiPhone = huaweiFactory.iphoneProduct();
huaweiPhone.start();
huaweiPhone.callup();
}
}
运行结果:
适用场景:客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量的重复代码提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体的实现
优点:
具体产品在应用层的代码隔离,无需关心创建的细节
将一个系列的产品统一到一起创建
缺点:
规定了所有可能被创建的产品集合,产品簇中扩展新的产品困难;
增加了系统的抽象性和理解难度
小结
简单工厂模式:虽然某种程度上不符合设计原则,但实际使用最多
工厂方法模式:不修改已有类的前提下,通过增加新的工厂类实现扩展
抽象工厂模式:不可以增加产品,可以增加产品族
(戏言:没有什么是加一层解决不了的)
学到最后,我们必须要清楚的知道一点,就是不要本末倒置了,我们学习设计模式是为了更好的设计软件,不要为了使用某种设计模式而去设计