设计模式之工厂模式
概念
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
简单说就是专门负责将大量有共同接口的类实例化,而且不必事先知道每次是要实例化哪一个类的模式。
它定义一个用于创建对象的接口,由子类决定实例化哪一个类。工厂模式相当于创建实例对象的new,经常要根据类Class生成实例对象。
意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决:主要解决接口选择的问题。
何时使用:我们明确地计划不同条件下创建不同实例时。
如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。
关键代码:创建过程在其子类执行。
应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 2、Hibernate 换数据库只需换方言和驱动就可以。
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口。
注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
简单工厂(静态工厂)
这里的例子借用《大话设计模式》里的那个计算器,不是刷广告哈。
这里是产品的抽象类
package com.design.factory;
public abstract class Operation {
protected double numberA = 0;
protected double numberB = 0;
public abstract double getResult() throws Exception;
public double getNumberA() {
return numberA;
}
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public double getNumberB() {
return numberB;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
}
具体的子类及实现方法:
加:
package com.design.factory.impl;
import com.design.factory.Operation;
public class OperationAdd extends Operation {
@Override
public double getResult() {
return numberA+numberB;
}
}
减:
package com.design.factory.impl;
import com.design.factory.Operation;
public class OperationSub extends Operation {
@Override
public double getResult() {
return numberA-numberB;
}
}
乘:
package com.design.factory.impl;
import com.design.factory.Operation;
public class OperationMul extends Operation {
@Override
public double getResult() {
return numberA*numberB;
}
}
除:
package com.design.factory.impl;
import com.design.factory.Operation;
public class OperationDiv extends Operation {
@Override
public double getResult() throws Exception {
if (numberB == 0)
throw new Exception("除数不能为0");
return numberA / numberB;
}
}
具体的加减乘除实现之后,就开始咱们的工厂了。
package com.design.factory.factory;
import com.design.factory.Operation;
import com.design.factory.impl.OperationAdd;
import com.design.factory.impl.OperationDiv;
import com.design.factory.impl.OperationMul;
import com.design.factory.impl.OperationSub;
public class Factory {
public static final int ADD = 1;
public static final int SUB = 2;
public static final int MUL = 3;
public static final int DIV = 4;
public static Operation getOperation(int operate) {
Operation oper = null;
switch (operate) {
case ADD:
oper = new OperationAdd();
break;
case SUB:
oper = new OperationSub();
break;
case MUL:
oper = new OperationMul();
break;
case DIV:
oper = new OperationDiv();
break;
}
return oper;
}
}
最后玩都行,计算器:
Operation operation = Factory.getOperation(Factory.ADD);
operation.setNumberA(5);
operation.setNumberB(6);
System.out.println(operation.getResult());
总结:
1 它是一个具体的类,非接口,抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
2 create()方法通常是静态的,所以也称之为静态工厂。
缺点:
扩展性差(我想增加一种算法,除了新增一个计算类,还需要修改工厂类方法)
多方法工厂
顾名思义,多方法工厂就是有多个方法,不再使用switch或者if来判断参数,直接调用并返回你想要的对象
package com.design.factory.factory;
import com.design.factory.Operation;
import com.design.factory.impl.OperationAdd;
import com.design.factory.impl.OperationDiv;
import com.design.factory.impl.OperationMul;
import com.design.factory.impl.OperationSub;
public class Factory {
public static Operation getAddResult() {
return new OperationAdd();
}
public static Operation OperationSub() {
return new OperationSub();
}
public static Operation OperationMul() {
return new OperationMul();
}
public static Operation OperationDiv() {
return new OperationDiv();
}
}
特点:想要添加一种计算,不会修改工厂类的具体方法,而是在工厂类中添加一个static方法及添加一个继承父类的计算实现类即可
抽象工厂
顾名思义抽象工厂呢,即为要抽象工厂角色
首先我们有一个加法的接口:
package com.design.factory;
public interface OperationAdd {
String getResult();
}
然后此接口的多个实现类:
因为懒,没有再去写别的例子,就多加了一个参数而已,勿怪勿怪
实现1:
package com.design.factory.impl;
public class OperationAdd implements com.design.factory.OperationAdd {
@Override
public String getResult() {
return "Test Aperation one";
}
}
实现2:
package com.design.factory.impl;
import com.design.factory.OperationAdd;
public class OperationAddMore implements OperationAdd {
@Override
public String getResult() {
return "Test Aperation two";
}
}
还是懒,就写这一个了,其他的都差不多。下面为抽象工厂
package com.design.factory.factory;
import com.design.factory.impl.OperationAdd;
import com.design.factory.impl.OperationDiv;
import com.design.factory.impl.OperationMul;
import com.design.factory.impl.OperationSub;
public abstract class Factory {
public abstract OperationAdd getAddResult();
}
然后是抽象工厂的实现
实现A:
package com.design.factory.factory;
import com.design.factory.impl.OperationAdd;
public class OperationFactoryA extends Factory {
@Override
public OperationAdd getAddResult() {
return new OperationAdd();
}
}
实现B:
package com.design.factory.factory;
import com.design.factory.OperationAdd;
import com.design.factory.impl.OperationAddMore;
public class OperationFactoryB extends Factory {
@Override
public OperationAdd getAddResult() {
return new OperationAddMore();
}
}
最后,不同的工厂实现不同的产品类型。
Factory factory1 = new OperationFactoryA();
factory1.getAddResult();
Factory factory2 = new OperationFactoryB();
factory2.getAddResult();
简单的抽象工厂模式demo就写完了,类似于这种组装逻辑,抽象工厂模式还是游刃有余,如果再增加一种加法的计算方式,我们会增加一个工厂实现类,如果在增加一种计算方式(减法,乘法,除法),那么又会增加一个计算的基类以及多种计算方式的实现类,同样的功能,抽象工厂模式会有很多类文件,这就是其缺点
(反射)简单工厂模式
其他还有通过反射,Class.forName(clz.getName()).newInstance()实现的简单工厂。以及,普通的直接在工厂方法返回new 对象 的工厂。这里就不做实例讲解了,没有什么必要。
总结
工厂模式重点就是适用于 构建同产品类型(同一个接口 基类)的不同对象时,这些对象new很复杂,需要很多的参数,而这些参数中大部分都是固定的,so,懒惰的程序员便用工厂模式封装之。
(如果构建某个对象很复杂,需要很多参数,但这些参数大部分都是“不固定”的,应该使用Builder模式)
说到底,我们获得的对象仍是父类对象,工厂中的实现为子类向上转型为父类,从这里我们可以看到,子类向上转型为父类,则会遗失掉父类中没有定义的方法,而除了private的属性外,其他的属性都会被父类的属性覆盖,跑题了。
总之,为了适应程序的扩展性,拥抱变化,便衍生出了 普通工厂、抽象工厂等模式。
本文参考文献
https://www.w3cschool.cn/shejimoshi/factory-pattern.html
http://blog.youkuaiyun.com/zhangerqing/article/details/8194653
http://blog.youkuaiyun.com/zxt0601/article/details/52798423
http://blog.youkuaiyun.com/u012359453/article/details/78825270
8万+

被折叠的 条评论
为什么被折叠?



