情景引入:
这一天,大雄满身是伤,头上也是几个大包,不用说,一定又是被胖虎欺负了。步履蹒跚的他又来找哆啦A梦要道具了,但是健忘的他只知道他需要的道具的具体功能,忘记道具的名字了。但是聪明的哆啦A梦知道哪些功能对应哪些道具(比如,飞行->竹蜻蜓,时空穿越->时光机,去任意地点->任意门……),所以当大雄朝哆啦A梦求情并说明所需的功能时,好心的哆啦A梦马上就从四次元百宝袋中拿出大雄需要的具体道具,大雄满心欢喜,拿到道具马上就溜了,哆啦A梦叫也叫不住他。。。
一、简介
简单工厂模式不是一种设计模式,而是一种编程习惯,它不是GOF的23种设计模式之一,但是它是工厂方法模式的一个引导。
简单工厂模式,又称为静态工厂方法模式,属于类创建型模式。
在该模式中,可以根据不同的参数返回不同的类实例对象。此外还专门定义了一个类用来创建其他类的实例,被创建的实例通常具有相同的父类。
二、具体内容
当你需要什么,只需传入一个参数,就可以获取到你所要的对象,并且期间你无须知道任何创建对象的细节。
三、结构组成
Factory(工厂类/角色)
核心角色,负责创建所有具体产品类的实例,其静态的工厂方法可以直接被外界调用,用以创建所需的具体产品对象。Product(抽象产品类/角色)
所有具体产品类的父类,负责描述所有具体产品类(实例)共有的公共接口。ConcreteProduct(具体产品类/角色)
继承自抽象产品类,一般有多个,工厂类的工厂方法创建的都是该角色的某一具体产品实例。
四、UML类图
五、情景例子的实现代码
将上面的情境用代码实现一番:
//抽象产品类(抽象道具类)
public abstract class DaoJu
{
public abstract void supplyDaoJu();
}
//具体产品类(竹蜻蜓道具类)
public class ZhuQingTingDaoJu extends DaoJu
{
@Override
public void supplyDaoJu()
{
System.out.println("给大雄竹蜻蜓");
}
}
//具体产品类(时光机道具类)
public class ShiGuangJiDaoJu extends DaoJu
{
@Override
public void supplyDaoJu()
{
System.out.println("给大雄时光机");
}
}
//具体产品类(任意门道具类)
public class RenYiMengDaoJu extends DaoJu
{
@Override
public void supplyDaoJu()
{
System.out.println("给大雄任意门");
}
}
//道具工厂类(哆啦A梦)
public class DaoJuFactory
{
public static DaoJu createDaoJu(String function)
{
DaoJu daoJu = null;
switch(function)
{
case "飞行":
daoJu = new ZhuQingTingDaoJu();
break;
case "时空穿越":
daoJu = new ShiGuangJiDaoJu();
break;
case "去任意地点":
daoJu = new RenYiMengDaoJu();
break;
}
return daoJu;
}
}
//客户端(大雄)
public class Client
{
public static void main(String[] args)
{
DaoJu daoJu = null;
daoJu = DaoJuFactory.createDaoJu("飞行");
daoJu.supplyDaoJu();
daoJu = DaoJuFactory.createDaoJu("时空穿越");
daoJu.supplyDaoJu();
daoJu = DaoJuFactory.createDaoJu("去任意地点");
daoJu.supplyDaoJu();
}
}
输出结果:
给大雄竹蜻蜓
给大雄时光机
给大雄任意门
六、优点
降低了程序的耦合度。将对象的创建过程与对象的使用过程分离,将对象的创建交给专门的工厂类负责。
创建所需的对象很方便。因为工厂类的工厂方法是静态方法,故我们可以直接通过类名调用工厂方法并传入相应参数来创建我们所需的对象实例。
实现了责任分割。工厂类含有判断逻辑代码,用以适时创建相应的产品实例,因此客户端便不必承担起直接创建产品对象的责任,而仅仅是“消费”/“使用”产品。
方便客户端的记忆。客户端不必记住所有具体产品类的类名,只需知道它们所对应的参数。特别是对于一些复杂的类名,通过简单工厂模式使得客户端只需记住其特征参数,便可使用特征参数来创建相应产品对象,减少客户端的记忆负担。
提高了系统的灵活性。在实际开发过程中,我们经常将具体产品对应的特征参数保存在XML等配置文件中,使得我们修改参数时无需修改客户端的代码。
七、缺点
工厂类的责任过重(不够灵活)。它集中了所有具体产品的创建逻辑代码。一旦增加新的产品,就要修改工厂类的判断逻辑代码,这一点与开闭原则相违背。一旦不能正常工作,整个系统便受到很大影响。
增加了系统中类的个数。这在一定程度上增加了系统的复杂度和理解难度,从而使得系统难以维护。
系统扩展困难。一旦增加新的产品,就要修改工厂类的判断逻辑代码,产品类型一多起来,就可能造成工厂逻辑过于复杂,不利于后期的扩展和维护。
工厂类不能被继承。由于工厂类使用了静态工厂方法,使得工厂类角色无法形成基于继承的等级结构。
八、什么时候用
工厂类负责创建的产品对象类型较少。
客户端只知道传入工厂类的参数,对于如何创建产品对象不必关心。
九、其他想说的
对于简单工厂模式,每次维护或拓展具体产品时都要改动工厂的代码,以致代码需重新编译部署。所以对于算法的时常变动,使用该模式不是最好的办法,而应考虑使用其他设计模式,比如策略模式。