大话设计模式一:简单工厂模式(simple factory)

时间:2022-02-11 20:33:24

一. 定义:

简单工厂提供一个创建对象实例的功能,而无须关心其具体实现。

简单工厂方法的内部主要实现的功能是:选择合适的实现类来创建实例对象。


二. 结构图:

大话设计模式一:简单工厂模式(simple factory)

Api:定义客户端所需要的功能接口

Impl:具体实现Api的实现类,可能会有多个

Factory:工厂,选择合适的实现类来创建Api接口对象

Client:客户端,通过Factory去获取Api接口对象,面向Api接口编程


三. 序列图:

大话设计模式一:简单工厂模式(simple factory)


四. 接口回顾:

1. 接口是用来干嘛的?

通常用接口来定义实现类的外观,就相当于一份契约,根据外部应用需要的功能,约定了实现类应该要实现的功能。

2. 接口的思想:封装隔离

3. 使用接口的好处:

只要接口不变,内部实现的变化就不会影响到外部应用,从而使系统更灵活

4. 接口和抽象类的选择:

优先选择接口

在如下情况下选抽象类:既要定义子类的行为,又要为子类提供公共的功能。


五. 简单工厂的例子:

实例1:

定义Operation抽象类,将各种操作解耦为各个类并实现Operation抽象类,这样可以降低了各种具体操作代码耦合性。总体来说,定义一个抽象类,然后若干类继承该抽象类并实现抽象方法,工厂会根据需要生成各种子类对象(多态)。

package simple_factory;

public abstract class Operation {
private double numberA = 0;
private double numberB = 0;
public double getNumberA() {
return numberA;
}
public double getNumberB() {
return numberB;
}
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
public abstract double GetResult() throws Exception;

public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Operation oper;
oper = OperationFactory.createOperation("+");
oper.setNumberA(1);
oper.setNumberB(2);
double result = oper.GetResult();
System.out.println(result);
}
}

class OperationAdd extends Operation {
@Override
public double GetResult() {
double result = 0;
result = this.getNumberA() + this.getNumberB();
return result;
}
}

class OperationSub extends Operation {
@Override
public double GetResult() {
double result = 0;
result = this.getNumberA() - this.getNumberB();
return result;
}
}

class OperationMul extends Operation {
@Override
public double GetResult() {
double result = 0;
result = this.getNumberA() * this.getNumberB();
return result;
}
}

class OperationDiv extends Operation {
@Override
public double GetResult() throws Exception {
double result = 0;
if (this.getNumberB() == 0)
throw new Exception("除数不能为0");
result = this.getNumberA() / this.getNumberB();
return result;
}
}

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;
}
}

用一个单独的类来做创建实例的过程,这就是工厂。如果现在还需要增加各种复杂运算,比如平方根,只需要增加运算子类继承Operation抽象类,同时修改运算类工厂。

注意:客户端在调用工厂的时候,需要传入参数,这就说明客户端必须知道每个参数的含义,也需要理解每个参数对应的功能处理。这就要求必须在一定程度上,向客户暴露一定的内部实现细节。


实例2:

使用反射加上配置文件,来实现添加新的实现类过后,无需修改代码,就能把这个新的实现类加入应用中。

/**
* 某个接口(通用的、抽象的、非具体的功能的)
*/
public interface Api {
/**
* 某个具体的功能方法的定义,用test来演示一下。
*/
public void test(String s);
}
/** * 对某个接口的一种实现  */public class Impl implements Api{public void test(String s) {System.out.println("Now In Impl. The input s: " + s);}}
/** * 工厂类,用来创造Api对象 */public class Factory {/** * 具体的创造Api的方法,根据配置文件的参数来创建接口 */public static Api createApi() {// 直接读取配置文件来获取需要创建实例的类(使用反射)InputStream in = null;Properties p = null;Api api = null;try {in = Factory.class.getResourceAsStream("FactoryTest.properties");p = new Properties();p.load(in);// 用反射去创建对象api = (Api) Class.forName(p.getProperty("ImplClass")).newInstance();} catch (Exception e) {e.printStackTrace();} finally {try {in.close();} catch (IOException e) {e.printStackTrace();}}return api;}}
配置文件:如果新增了实现类后,修改此配置文件就可以了
ImplClass=cn.javass.dp.simplefactory.myexample.Impl
/** * 客户端:测试使用Api接口 */public class Client {public static void main(String[] args) {Api api = Factory.createApi();api.test("哈哈,不要紧张,只是个测试而已!");}}

六. 何时使用简单工厂:

1. 如果想要完全封装隔离具体实现,让外部只能通过接口来操作封装体,那么可以选择简单工厂,让客户端通过工厂来获取相应的接口,而无需关心具体实现。

2. 如果想要把对外创建对象的职责集中管理和控制,可以选用简单工厂,把对外创建对象的职责集中到一个简单工厂来,从而实现集中管理和控制。