简述
工厂模式是最常见的一类创建型设计模式。通常说的工厂模式是指工厂方法模式。这里讲的简单工厂模式是工厂方法模式的“小弟”,它不属于GoF 23种设计模式,但是使用比较频繁,
简单工厂模式定义: 定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
UML类图
- Factory: 工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例;工厂类可以被外界直接调用,创建所需的产品对象
- Product: 抽象产品类,他是工厂类创建的所有对象的父类,封装了各种产品的公共方法,他的引入提高了系统的灵活性
- ConcreteProduct: 具体产品角色,它是简单工厂模式的创建目标。
要点
- 所有的具体产品类都继承于Product类
- 工厂类中提供了静态的工厂方法,用来创建Product
- 工厂类中必须传入参数,来决定创建哪个具体的产品
案例
在IM开发过程中,因为引入了不同账号体系的概念,所以需要根据不同的账号类型创建不同的账号信息。
简单工厂模式实现过程如下:
- 定义账号产品父类
public Abstract class AcctBase {
……
// 不同的账号体系加密方式不一样
public Abstract void getEncryPwd();
……
}
- 定义具体的子类
//IM 账号
public class IMAcct Extends AcctBase{
……
public String getEncryPwd() {
//IM账号的加密处理
}
……
}
//XX 体系账号
public class XXAcct Extends AcctBase{
……
public String getEncryPwd() {
//XX账号的加密处理
}
……
}
- 定义账号类型,用于工厂方法的参数
Interface AcctType {
int ACCT_TYPE_IM = 0;
int ACCT_TYPE_XX = 1;
}
- 创建工厂类
public class AcctFactory {
public static AcctBase createAcct(int acctType) {
AcctBase acct = null;
switch (acctType) {
case AcctType.ACCT_TYPE_IM:
acct = new IMAcct();
break;
case AcctType.ACCT_TYPE_XX:
acct = new XXAcct();
break;
default:
break;
}
return acct;
}
}
main程序中的使用代码就应该如下:
class Client {
public static void main(String args[]) {
AcctBase acct = AcctFactory.createAcct(AcctType.ACCT_TYPE_IM);
String encryedPwd = acct.getEncryPwd();
System.out("encryedPwd = " + encryedPwd);
}
}
大家可以想象上面如果不用简单工厂模式,所有的实现都在一个Acct类中通过if-else处理完成, 后面再添加多个账号类型,可想而知Acct类会非常臃肿庞大,极难维护。
创建对象
与一个对象相关的职责通常有3类: 对象本身的职责,创建对象,使用对象。
对象本身的职责就是对象自身所具有的一些数据和行为。
在Jave中,通常有以下几种创建对象的方式:
- 使用new 关键字直接创建对象
- 通过反射机制创建对象
- 通过clone方法创建对象 (属于原型模式)
- 通过工厂类创建。
这里有一点要注意,一个类中不能存在既创建对象,又使用对象的情况,这违背单一职责原则。
总结
优点:
- 简单工厂模式实现了对象创建和使用的分离
- 客户端不需要知道具体的创建细节,只需要知道具体产品类对应的参数即可,减少了一些类的记忆。
缺点:
- 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能工作,整个系统都会受到影响
- 使用简单工厂模式肯定会增加系统类的个数,增加系统的复杂性和理解难度
- 系统扩展困难,每次新增产品类,都会涉及到工厂类的修改,违背开闭原则
- 因为工厂类使用的是静态工厂方法,造成工厂角色无法形成基于继承的等级结构
适用场景
- 工厂类负责创建的对象较少,因为对象不多,所以工厂业务不会太复杂
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心