写点什么

FactoryMethodPattern- 工厂方法模式

作者:梁歪歪 ♚
  • 2022 年 5 月 28 日
  • 本文字数:3459 字

    阅读完需:约 11 分钟

工厂模式有三种:简单工厂模式,工厂方法模式,抽象工厂模式。其中,简单工厂模式不属于 23 中设计模式。本篇文章会通过从简单工厂模式过渡到工厂方法模式的方式呈现。

一、简单工厂模式

简单工厂模式(Simple Factory Pattern):指的是由一个工厂对象来决定创建具体的产品实例,简单工厂模式并不属于 23 中设计模式,但是在我们平常运用的非常广泛。


下面我通过一个农场里面种植水果来举例实现简单工厂模式。



  • 新建一个产品接口IProduct.java,接口中定义一个种植方法。


package cn.liangyy.simple;
/** * 产品接口 */public interface IProduct { /** * 种植水果 */ void grow();}
复制代码


  • 新建一个苹果类Apple.java来实现接口


package cn.liangyy.simple;
/** * 苹果类 */public class Apple implements IProduct { /** * 种植水果 */ @Override public void grow() { System.out.println("种植苹果"); }}
复制代码


  • 新建一个橘子类Orange.java来实现接口


package cn.liangyy.simple;
/** * 橘子类 */public class Orange implements IProduct { /** * 种植水果 */ @Override public void grow() { System.out.println("种植橘子"); }}
复制代码


按照我们普通的写法,如果创建 Apple 和 Orange 对象的话,直接 new 出来就好了,但是这种方式很不友好,一旦一个对象的创建非常复杂,就会给我们带来极大的不方便,所以我们新建一个工厂类来帮助我们创建具体的产品类,从而隐藏创建对象的细节。


  • 新建一个简单工厂类SimpleFactory.java来创建产品


package cn.liangyy.simple;
/** * 简单工厂类 */public class SimpleFactory { public IProduct createProduct(String productType){ if ("apple".equals(productType)){ return new Apple(); }else if ("orange".equals(productType)){ return new Orange(); } return null; }}
复制代码


  • 新建测试类TestSimpleFactory.java来测试一下


package cn.liangyy.simple;
/** * 简单工厂-测试类 */public class TestSimpleFactory { public static void main(String[] args) { SimpleFactory factory = new SimpleFactory(); IProduct apple = factory.createProduct("apple"); apple.grow(); //输出:种植苹果
IProduct orange = factory.createProduct("orange"); orange.grow(); //输出:种植橘子 }}
复制代码


这时候我们就将创建细节隐藏了,全部产品都通过 SimpleFactory 来帮忙创建,但是这种写法依旧存在问题:

​ 1、假如我调用 createProduct()方法参数写错了,比如 apple 拼错了,这时候代码编译时可以通过的,运行时才能发现问题。

​ 2、 如果产品很多,那么 SimpleFactory 类中就会产生大量的 if 分支,效率降低

所以为了解决这个问题,我们再优化一下 SimpleFactory 类中的 createProduct()方法。


  • 优化 SimpleFactory 类,新增一个 createProduct2()方法


package cn.liangyy.simple;
/** * 简单工厂类 */public class SimpleFactory { /** * 普通方法 * @param productType * @return */ public IProduct createProduct(String productType){ if ("apple".equals(productType)){ return new Apple(); }else if ("orange".equals(productType)){ return new Orange(); } return null; }
/** * 优化方法 * @param clazz * @return * @throws Exception */ public IProduct createProduct2(Class<? extends IProduct> clazz) throws Exception { if (null == clazz){ throw new Exception("无法识别的产品"); } return clazz.newInstance(); }}
复制代码


  • 同时,我们新建一个测试类TestSimpleFactory2.java,调用优化方法获取产品对象。


package cn.liangyy.simple;
/** * 简单工厂-测试优化后的方法 */public class TestSimpleFactory2 { public static void main(String[] args) throws Exception { SimpleFactory factory = new SimpleFactory(); IProduct apple = factory.createProduct2(Apple.class); apple.grow(); //输出:种植苹果
IProduct orange = factory.createProduct2(Orange.class); orange.grow(); //输出:种植橘子 }}
复制代码


由上可以看出,这种写法完美的解决了第一种存在的问题(不过需要强调的是,我们的工厂类一般要将创建对象实例的方法设置成静态方法)。


简单工厂模式使用场景


适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。


简单工厂模式存在的问题


假如每种产品创建不仅仅只是实例化一个对象,还有其它逻辑需要处理,那么我们无法直接使用一句反射语句来创建对象,所以还是避免不了要写很多 if 或者 switch 循环分支。这样每新增一个产品我们都需要修改简单工厂类,违背了开闭原则,而且随着产品越来越丰富,工厂的职责会变得越来越多,久而久之会越来越难以维护。


为了弥补简单工厂方法的不足之处,所以就有了工厂方法模式。

二、工厂方法模式

工厂方法模式:Fatory Method Pattern,主要用来解决简单工厂模式存在的问题。其是指定义一个创建对象的接口,然后创建不同的具体工厂来创建对应的产品。工厂方法让类的实例化推迟到工厂子类中进行,在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节。


工厂方法模式中假如需要新增产品,只需要再新建工厂实现类,无需修改源码,符合开闭原则。


我们依旧通过农场里面种植水果来实现工厂方法模式。



  • 新建一个产品接口IProduct.java


package cn.liangyy.method;
/** * 产品接口 */public interface IProduct { void grow();}
复制代码


  • 新建苹果产品类Apple.java


package cn.liangyy.method;
/** * 苹果类 */public class Apple implements IProduct { @Override public void grow() { System.out.println("种植苹果"); }}
复制代码


  • 新建橘子产品类Orange.java


package cn.liangyy.method;
/** * 橘子类 */public class Orange implements IProduct { @Override public void grow() { System.out.println("种植橘子"); }}
复制代码


  • 新建一个工厂接口IFarmFactory.java,将工厂也抽象化


package cn.liangyy.method;
/** * 工厂接口 */public interface IFarmFactory { /** * 创建产品 * @return */ IProduct create();}
复制代码


  • 新建苹果工厂类AppleFactory.java


package cn.liangyy.method;
/** * 苹果工厂 */public class AppleFactory implements IFarmFactory { /** * 创建产品 * * @return */ @Override public IProduct create() { return new Apple(); }}
复制代码


  • 新建橘子工厂类OrangeFactory.java


package cn.liangyy.method;
/** * 橘子工厂 */public class OrangeFactory implements IFarmFactory { /** * 创建产品 * * @return */ @Override public IProduct create() { return new Orange(); }}
复制代码


  • 测试类TestFactoryMethod.java


package cn.liangyy.method;
/** * 工厂方法测试类 */public class TestFactoryMethod { public static void main(String[] args) { IFarmFactory appleFactory = new AppleFactory(); IProduct apple = appleFactory.create(); apple.grow(); //输出:种植苹果
IFarmFactory orangeFactory = new OrangeFactory(); IProduct orange = orangeFactory.create(); orange.grow(); //输出:种植橘子 }}
复制代码


到这里,想必大家都明白工厂方法和简单工厂的区别了吧。


  • 简单工厂:所有的产品都有一个工厂类一个方法来创建

  • 工厂方法:将工厂抽象化,将其职责细化,每种产品都由特定的工厂来生产,这也是单一职责原则的体现


工厂方法模式的使用场景


  • 创建对象需要大量重复代码

  • 客户端(应用层)不依赖与产品类实例如何被创建、实现等细节

  • 一个类通过其子类来指定创建哪个对象


工厂方法模式的缺点


每增加一个产品就得需要新增两个类,一旦产品数量上去了,类的个数也会随之增加,这样一来增加了系统的复杂度,也会使得系统过于抽象、难以理解。

发布于: 刚刚阅读数: 3
用户头像

梁歪歪 ♚

关注

还未添加个人签名 2021.07.22 加入

还未添加个人简介

评论

发布
暂无评论
FactoryMethodPattern-工厂方法模式_设计模式_梁歪歪 ♚_InfoQ写作社区