工厂设计模式
Posted 让学习如呼吸般自然
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了工厂设计模式相关的知识,希望对你有一定的参考价值。
工厂设计模式:是一种创建对象的模式,使代码的耦合。工厂模式就是给外部批量提供相同或者不同的产品,而外部不需要关心工厂是如何创建一个复杂产品的过程.所以工厂模式可以降低模块间的耦合,同时可以提高扩展性(当有新的产品出现时,只需要扩展工厂就行了,上层模块不敏感).
1:创建一个接口或者抽象类
2:实现接口(产品类)
3:创建一个工厂类:在工厂类里面创建对象(产品的实例化类)
4:在客户端创建工厂,得到我们想要创建的对象(客户端的引用)
1.)标准工厂方法模式
首先先介绍一下标准的工厂方法模式,不带任何的变种.以工厂生产不同操作系统的手机为例.
建立一个产品接口,提供一个获取系统信息的方法.
/** * Created by jesse on 15-8-17. */ public interface IPhone { public void getOS(); }
再根据IPhone接口实现android,ios,Blackberry三种手机.
public class AndroidPhone implements IPhone { private final String TAG = AndroidPhone.class.getSimpleName(); @Override public void getOS() { Log.i(TAG, "im Android"); } } public class IosPhone implements IPhone { private final String TAG = IosPhone.class.getSimpleName(); @Override public void getOS() { Log.i(TAG, "im IOS"); } } public class BlackBerryPhone implements IPhone { private final String TAG = BlackBerryPhone.class.getSimpleName(); @Override public void getOS() { Log.i(TAG, "im BlackBerry"); } }
标准的工厂方法模式都需要有抽象的工厂接口或者基类.
public abstract class IGenerator { public abstract IPhone generatePhone(String flag) throws Exception; }
通过基类或者接口来实现真实的工厂类,这里需要注意跟简单工厂模式的不同,标准的工厂方法模式里面一个工厂只生产一个产品,所以这里要根据产品的种类划分出来三个工厂,分别生产三种不同的产品.这种设计思想非常契合单一职责原则.
public class AndroidGenerator extends IGenerator { @Override public IPhone generatePhone() { return new AndroidPhone(); } } public class IOSGenerator extends IGenerator { @Override public IPhone generatePhone() { return new IosPhone(); } } public class BlackberryGenerator extends IGenerator { @Override public IPhone generatePhone() { return new BlackBerryPhone(); } }
在客户端从工厂中获得产品并使用的过程中都是通过接口进行访问的,在创建产品的阶段有效得降低了使用者和产品之间的耦合度.
AndroidGenerator androidGenerator = new AndroidGenerator();
IOSGenerator iosGenerator = new IOSGenerator();
BlackberryGenerator bbGenerator = new BlackberryGenerator();
android = androidGenerator.generatePhone();
ios = iosGenerator.generatePhone();
bb = bbGenerator.generatePhone();
android.getOS();
ios.getOS();
bb.getOS();
2).简单工厂模式
接着分析一下简单工厂模式,这是最简单的变种,也叫做静态工厂方法模式,从这个名字就可以看出工厂的方法是静态的.既然工厂方法是静态的,那么工厂就不能通过继承进行扩展,如果有新增的产品,就只能在方法里面做修改所以从这个角度来说简单工厂模式是不符合开闭原则的.(工厂就是一个简单的类,不是抽象类和接口) 因为这是静态工厂方法模式,所以工厂类就没有接口或者虚基类来提供抽象.通过不同的Flag来初始化不同的产品.
总结一句:简单工厂设计模式就是在一个工厂中实例化出来所有的产品,所以要实例化的对象发生变化的时候,工厂还是要发生变化,所以体验还是不太好。
public class PhoneGenerator{ public final static String GENERATE_IOS = "generate_ios"; public final static String GENERATE_ANDROID = "generate_android"; public final static String GENERATE_BLACKBERRY = "generate_blackberry"; public static IPhone generatePhone(String flag) throws Exception { IPhone iPhone = null; switch (flag){ case GENERATE_ANDROID: iPhone = new AndroidPhone(); break; case GENERATE_IOS: iPhone = new IosPhone(); break; case GENERATE_BLACKBERRY: iPhone = new BlackBerryPhone(); break; default: throw new Exception("UNDEFINED FLAG"); } return iPhone; } }
对外部来说要使用工厂只需要把目标产品类传过去就行了.运行结果跟1)中的是一样的.
3)结合反射的应用
假设需要加入一种搭载win10系统的手机,标准的工厂方法模式需要重新派生出来一个新的工厂来给客户使用,简单工厂模式也需要新增新的flag和case判断去构造新的手机.有没有什么方法可以尽量避免这些修改呢?当然是有的,这里可以通过使用Class.forName 反射的方式来达到目的.
首先通过泛型来约束输入输出的参数类型,把异常抛到上层去处理并实现具体的工厂.
public abstract class IGenerator { public abstract <T extends IPhone>T generatePhone(Class<T> clazz) throws Exception; }
public class PhoneGenerator extends IGenerator { public <T extends IPhone>T generatePhone(Class<T> clazz) throws Exception { IPhone iPhone = null; iPhone = (IPhone) Class.forName(clazz.getName()).newInstance(); return (T)iPhone; } }
通过这种装载的方式去初始化产品就可以达到上面描述的需求,可以根据需求直接添加一个实现了IPhone接口的WindowsPhone产品而不需要修改工厂,客户就可以直接从工厂拿到WindowsPhone的手机去使用了.
以上是关于工厂设计模式的主要内容,如果未能解决你的问题,请参考以下文章
设计模式简单工厂模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )