工厂模式
-
工厂模式:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推到具体的子工厂类当中。实现创建型模式中的“创建与使用相分离”。
-
按实际业务场景,工厂模式有3中不同的实现方式:简单工厂模式、工厂方法模式和抽象工厂模式。
-
将被创建的对象称为产品,创建商品的对象称为工厂。
简单工厂模式
当创建的产品不多时,一个工厂类就可以完成。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。使用这个模式可以把对象的创建和对象的使用分离分开,工厂只负责对象的创建,客户端程序调用和使用对象,客户端程序无需创建对象。对象的创建放在一起,方便维护和扩展。
程序:可复用、可维护、可拓展、灵活性好
简单工厂模式的优点:
1)将对象的创建和对象本身业务处理分离可以降低系统的耦合度,使得两者修改起来都相对容易;
2)在调用工厂类的工厂方法时,由于工厂方法是静态方法,使用起来很方便,可通过类名直接调用,而且只需要传入一个简单的参数即可;对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量;
3)通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
简单工厂模式的缺点:
1)由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
2) 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
3)系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
适用环境:
适用于工厂类创建的对象少且客户端对传入工程类参数不关心的情况下。
题目示例:
实现一个简单的计算器应用程序。
功能要求:
1) 只需要实现+、-、*、、/四种运算;
2) 程序运行时,输入两个数和运算符号,即可得到运算结果。
例子目录结构如图所示:
Operation
public class Operation {
private double _numberA=0.0;
private double _numberB=0.0;
public void set_numberA(double _numberA) {
this._numberA = _numberA;
}
public void set_numberB(double _numberB) {
this._numberB = _numberB;
}
public double get_numberA() {
return _numberA;
}
public double get_numberB() {
return _numberB;
}
public double GetResult(){
double result=0.0;
return result;
}
}
OperationAdd,另外OperationSub等三种运算代码与其相似。
public class OperationAdd extends Operation{
public double GetResult() {
double result=0.0;
result=this.get_numberA()+this.get_numberB();
return result;
}
}
OperationFactory简单工厂创建静态实例,包含必要的逻辑判断,决定什么时候创建出哪一个产品的实例。
public class OperationFactory {
public static Operation createOperation(String operate) {
Operation oper = null;
switch (operate) {
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
Test相当于客户端,其不需要知道所创建具体产品的类名,只需要知道参数。此处的参数通过strOperate
获得。
public class Test {
public static void main(String[] args) {
try
{
Scanner input =new Scanner(System.in);
System.out.print("请输入数字A: ");
String strNumberA = input.nextLine();
System.out.print("请选择运算符号(+、-、*、/): ");
String strOperate = input.nextLine();
System.out.print("请输入数字B: ");
String strNumberB = input.nextLine();
double result;
Operation oper;
oper= OperationFactory.createOperation(strOperate);
oper.set_numberA(Double.valueOf(strNumberA));
oper.set_numberB(Double.valueOf(strNumberB));
result=oper.GetResult();
System.out.println("结果是" + result);
}
catch (Exception e)
{
System.out.println("除数不能为零");
}
}
}
UML如图所示:
注意:
- 如果程序报错,记得看一下上面有没有导入了包。程序可能因为导入同名包,而没有使用package下的自己写的类而报错。
- 可以通过引入配置文件,在不修改Test代码的情况下更换和添加新的操作。
模式的结构与实现:
简单工厂模式的主要角色如下:
- 简单工厂(SimpleFactory):是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。相当于示例中的
OperationFactory
,其创建产品的方法createOperation
可以被Test直接调用。 - 抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。相当于
Operation
类。 - 具体产品(ConcreteProduct):是简单工厂模式的创建目标。示例中
OperationAdd
等。
结构图如下:
工厂方法模式
工厂方法模式要求有一个抽象的工厂类,然后在抽象工厂类中定义一个生成产品的方法,这个方法就是工厂方法,这也是工厂方法模式的由来。该方法具体的行为会由它的子类或实现类来实现。 如果想生产某种产品,就定义一个新的产品和新的产品工厂类,这样就实现了不同的产品进行不同的创建,原来写好的代码不会发生变化。这种方式符合开闭原则,可扩展性比较好。适用于具体产品经常变化的情况。
工厂方法模式的优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
- 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。此处是对简单工厂的改进。
- 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
工厂方法模式的缺点:
- 类的个数容易过多,增加复杂度。
- 增加了系统的抽象性和理解难度。
- 抽象产品只能生产一种类型的产品,此弊端可使用抽象工厂模式解决。
适用环境:
- 客户只知道创建产品的工厂名,而不知道具体的产品名的情况下。
- 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
示例
修改以上的例子:
Operation
类以及OperationAdd
相似的类和之前简单工厂模式相同。
修改后目录如下:
客户端Test使用了配置文件和反射技术。关于反射技术的简述见:https://blog.csdn.net/Suzerk/article/details/120394593
public class Test {
public static void main(String[] args) {
try {
Properties properties=new Properties();
File file=new File("src\\Operation.properties");
properties.load(new FileInputStream(file));
// 反射技术 下面两种方式都可以
// Operation oper=(Operation)Class.forName(properties.getProperty("Operation")).newInstance();
IFactory operFactory=(IFactory)Class.forName(properties.getProperty("FactoryName")).newInstance();
Operation oper=operFactory.CreateOperation();
Scanner input=new Scanner(System.in);
System.out.print("请输入数字A: ");
String strNumberA = input.nextLine();
System.out.print("请输入数字B: ");
String strNumberB = input.nextLine();
double result = 0.0;
oper.set_numberA(Double.valueOf(strNumberA));
oper.set_numberB(Double.valueOf(strNumberB));
result = oper.GetResult();
System.out.println("结果是:"+result);
}
catch (Exception e){
System.out.println("除数不能为零");
}
}
}
配置文件,通过修改配置文件来创建不同的具体商品。
#Operation=OperationAdd
#Operation=OperationDiv
Operation=OperationMul
#Operation=OpOerationSub
#FactoryName=AddFactory
# FactoryName= SubFactory
FactoryName=MulFactory
# FactoryName= DivFactory
定义新的产品工厂类,以SubFactory
为例,其他的相似。
public class SubFactory implements IFactory{
public Operation CreateOperation()
{
return new OperationSub();
}
}
Java接口IFactory
public interface IFactory {
Operation CreateOperation();
}
模式的结构与实现
工厂方法模式由抽象工厂、具体工厂、抽象产品和具体产品等4个要素构成。
工厂方法模式的主要角色如下。
- 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。示例中的
IFactory
就是抽象工厂角色,访问具体工厂的工厂方法CreateOperation()
。 - 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。以
SubFactory
为例。 - 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
结构图如下:
抽象工厂
抽象方法是对工厂方法模式的一种改进,考虑多种类型的产品的生产。是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
适用环境:
- 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
- 系统一次只可能消费其中某一族产品,即同族的产品一起使用。
抽象工厂模式的优点:
除了具有工厂方法模式的优点外,其他主要优点如下。
- 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
- 当需要产品族时,抽象工厂可以保证客户端始终只使用同一个产品的产品组。
- 抽象工厂增强了程序的可扩展性,当增加一个新的产品族时,不需要修改原代码,满足开闭原则。
抽象工厂模式的缺点:
当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度。
示例
此处举一个新的关于搭配衣服的实例:
程序结构如下:
抽象工厂类AbstractClothesFactory:
//抽象工厂类
public abstract class AbstractClothesFactory {
//产品组装
//抽象方法:创建一件上衣
abstract public AbstractCoat CreateCoat();
//抽象方法:创建一件裤子
abstract public AbstractTrousers CreateTrousers();
}
抽象产品类AbstractCoat如下,AbstractTrousers相似。
//抽象产品类--上衣
public abstract class AbstractCoat
{
protected String style = "";
public String getStyle() {
return style;
}
}
具体工厂类CasualSuitFactory继承了AbstractClothesFactory,如下。FashionSuitFactory类似。
public class CasualSuitFactory extends AbstractClothesFactory{
public AbstractCoat CreateCoat()
{
return new CoatCasual();
}
public AbstractTrousers CreateTrousers()
{
return new TrousersCasual();
}
}
CoatCasual类如下,TrousersCasual相似。
public class CoatCasual extends AbstractCoat {
public String getStyle() {
return style="Casual";
}
}
Test
public class Test {
public static void main(String[] args) {
AbstractCoat myCoat;
AbstractTrousers myTrousers;
// AbstractClothesFactory factory = new CasualSuitFactory();
AbstractClothesFactory factory = new FashionSuitFactory();
myCoat= factory.CreateCoat();
myTrousers = factory.CreateTrousers();
System.out.println("上衣: "+ myCoat.getStyle());
System.out.println("裤子: "+myTrousers.getStyle());
}
}
模式的结构与实现
抽象工厂模式同工厂方法模式一样,也是由抽象工厂、具体工厂、抽象产品和具体产品等 4 个要素构成,但抽象工厂中方法个数不同,抽象产品的个数不同。
抽象工厂模式的主要角色如下。
- 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
- 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
- 对于抽象工厂,可以进一步利用反射技术和配置文件进行改进,只用一个工厂类,见:https://blog.csdn.net/Suzerk/article/details/120619872
参考资料:
http://c.biancheng.net/view/1351.html