似乎世界运行的规律就是越是更高级越是更简单,越是更简单更容易标准化,一旦标准化模式形成,按照这个标准可以衍生出无数个符合此标准的产品或者服务。在这里我介绍一种工厂方法模式,这种模式的使用频率可能是最高的,在平时的生活和工作中也颇为常见。
工厂方法模式,咋一听就好像这种模式的产生是从工业时代的工厂里面总结出来的,不过也不必追究溯源,掌握其精髓才是重中之重。
不管三七二十一,先来领略一下工厂方法模式的概念,由浅入深,深入浅出的了解更能便于理解和掌握。 官方定义:是这么说的,定义一个用于创建对象的接口,但是让子类决定具体实例化哪一个类。工厂方法使一个类的实例化延迟到了子类。 通俗释义:抽象类或者接口给你定义好,也就是先进行高度抽象的定义,然后子类产品进行具体实现,工厂根据具体需要创建相应的产品。 如果上面的定义没有看懂,其实没有关系,重点在理解意会,我相信多看几遍其义自见。再不行,看看下面的图,加深理解,正所谓图文并茂,效果更好。 通用类图:
创建抽象产品类,也就是定义一个公共的通用接口或抽象类,方便具体的子类实现或继承。
/** * @Description:抽象产品类 */ public abstract class AbstractProduct { //声明抽象方法 public abstract void create(); //其他方法 public void otherMethod() { //相关业务逻辑 } }此时就可以如法炮制,具体子类就可以继承抽象产品,来实现自己的产品创建细节。
/** * @Description:具体子类1 */ public class ConcreteProduct1 extends AbstractProduct { @Override public void create(){ //具体实现细节1 } } /** * @Description:具体子类2 */ public class ConcreteProduct2 extends AbstractProduct { @Override public void create(){ //具体实现细节2 } }以上产品定义好了,接下来就需要地方去创建这些产品,那么产品是在哪里创建的呢,那当然是工厂了。那么直接来个具体工厂创建就可以了吗,不不不,必须要站在一定的高度看问题,我们写程序必须要有起码的可读性和可维护性,所以先来创建一个抽象工厂,然后由交给具体工厂去创建产品。
/** * @Description:抽象工厂嘞 */ public abstract class AbstractFactory { //根据具体参数(枚举,字符串,Class等),创建相应的产品对象 public abstract <T extends AbstractProduct> T createProduct(Class<T> c); } /** * @Description:具体创建工厂类 */ public class ConcreteCreator extends AbstractFactory { @Override public <T extends AbstractProduct> T createProduct(Class<T> c) { AbstractProduct product = null; //通过反射获取产品实例 try { product = (AbstractProduct) Class.forName(c.getName()).newInstance(); } catch (Exception e) { e.printStackTrace(); } return (T) product; } }以上就是整个工厂方法模式的通用代码,其实在实际开发工作中,很多模式的代码都开发好了,基本上都是些业务逻辑代码处理,但是要是进行代码重构或者进行新产品的设计的时候,这个时候框架型的代码就很重要。
1.关于工厂方法模式的使用场景真的是太多了,例如在创建像每日必抢,促销直降以及更多类型的活动的时候,关于活动的管理以及活动的相关状态变化等维护,都可以考虑使用工厂方法模式,当然这种模式不一定是最好的,只有合适的场景下采用合适的设计模式才是最优的。 2.异常项目当中的使用,尤其是对接不同类型的外部接口,可以采用此种设计模式来满足不同类型业务场景。
关于工厂方法模式的优缺点,更多的是突出其优点,更何况我们使用某个产品都是看中其优点,发挥其优势作用,毕竟瑕不掩瑜嘛!工厂方法模式是典型的解耦框架,符合三个原则,第一,符合迪米特原则:高层模块需要知道抽象类,其他的实现不必了解,所以知道你该知道的,其余让她随风吧!第二,符合依赖倒置原则:高层模块不依赖于底层模块,两者都应该依赖于抽象;抽象不应该依赖细节,细节应该依赖抽象。第三,当然也符合里氏替换原则:只要父类能出现的地方,子类也能出现。 优点: 1.良好的封装性。这种代码的风格是非常的优秀的,而且结构清晰可读性高,同时此类代码的可维护性也非常的高。 2.良好的扩展性。由于具有高度的扩展性,对于项目或产品的开发是非常有优势的,能够支持业务快速迭代。 3.屏蔽实现细节。也就是我们在进行调用的时候,只关注接口是否变化,具体的实现细节是完全没有必要关心的。 缺点: 在进行扩展的时候,子类可能扩展无限多,不过此类场景也非常的少见,如果使用恰当,还是能发挥巨大作用的。
工厂方法模式也是有非常多的经典应用,阅读这些代码,可以加深对工厂方法模式的理解。
public abstract class Calendar public abstract class NumberFormat public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>本例子是在项目中对频道活动与促销直降活动的一个小重构,创建活动是非常复杂的,包括很多校验规则,我这里知识抽象一下,把框架抽出来演示一下工厂模式的实际应用,和通用代码差不多的,可以参考理解一下。
/** * @Description:活动服务接口 */ public interface ActivityService { /** * 声明活动创建公共方法 * @param form * @param context * @throws Exception */ void createAct(ActivityForm form, Map<String, Object> context) throws Exception; } /** * @Description:频道活动服务类 */ public class ChannelActivityService implements ActivityService{ @Override public void createAct(ActivityForm form, Map<String, Object> context) throws Exception { //频道活动创建 } } /** * @Description:促销直降活动服务类 */ public class PromotionActivityService implements ActivityService{ @Override public void createAct(ActivityForm form, Map<String, Object> context) throws Exception { //促销直降活动创建 } } /** * @Description:活动服务工厂类 */ public class ActivityServiceFactory { public ActivityService create(Integer type){ if (type == null){ return null; } if (type == 1)return new ChannelActivityService(); if (type == 2)return new PromotionActivityService(); throw new RuntimeException("不存在的活动类型"); } } /** * @Description:活动创建调用方 */ public class ActivityCreator { public static void main(String[] args) throws Exception{ ActivityForm form = new ActivityForm(); ActivityServiceFactory factory = new ActivityServiceFactory(); ActivityService activity = factory.createActivity(1); activity.createAct(form,null); } }以上就是工厂方法模式的介绍,本身内容比较简单,但是要是能结合实际应用在工作中,我想帮助还是比较大的,尤其现在的项目系统体量不可谓不复杂,要抽出一些时间去应用设计模式重构是非常艰难的,但是还是要有这种意识,老代码都是一步一步慢慢重构出来的,今天抽出一个私有类,明天创建个辅助类,后天设计模式优化一下,这样慢慢的迭代优化就会有非常不错的成长,加油!