创建型模式之工厂模式以及对应框架用到的源码

工厂模式

  • 前言
    • 工厂模式定义
    • 工厂模式意义
    • 工厂模式分类
  • 简单工厂
      • 模式结构图
      • 代码示例
      • 框架源码中应用
      • 优缺点
  • 工厂方法
      • 模式结构图
      • 代码示例
      • 框架源码中应用
      • 优缺点
  • 抽象工厂
      • 模式结构图
      • 代码示例
      • 框架源码中应用
      • 优缺点
  • 总结
  • 感谢与参考

前言

本期小编继续带大家来了解设计模式,这次为大家带来比较实用的模式,创建型模式。创建型模式主要是为了将系统与它的对象创建、结合、表示的方式分离。这些设计模式在对象创建的类型、主体、方式、时间等方面提高了系统的灵活性。这个模式大家在实际业务场景中也是应用最多的,比方说spring ioc容器那个工厂(这个比较复杂),当然最为熟悉的就是工厂和单例模式。接下来小编为大家介绍一下工厂模式。

工厂模式定义

工厂模式:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。这边理解的话就是标准化构建对象。

工厂模式意义

  • 降低对象构建的复杂性(当对象构建非常复杂时,交由工厂构建不需要关注其复杂实现)。
  • 对象的复用(Ioc对象的复用)。
  • 标准化生产,统一加工处理比方装饰和代理(MyBatis中执行器的创建)。

工厂模式分类

工厂模式主要分三类:简单工厂模式,工厂方法模式以及抽象方法模式,下面小编会通过结构图,代码示例,在源码中的应用来一个个分别讲解。

简单工厂

模式结构图

创建型模式之工厂模式以及对应框架用到的源码_第1张图片
上面结构图非常简单,下面小编写个示例代码

代码示例

public class SimpleFactory {
     

    public static void main(String[] args) {
     
        SimpleFactory simpleFactory = new SimpleFactory();
        Phone apple = simpleFactory.createPhone("apple");
        apple.sendMsg();
    }

    public Phone createPhone(String name) {
     
        if ("apple".equals(name)) {
     
            return new ApplePhone();
        } else if ("xiaomi".equals(name)) {
     
            return new XiaomiPhone();
        } else {
     
            throw new IllegalArgumentException("不支持类型手机");
        }
    }

    interface Phone {
     
        void sendMsg();
    }

    class ApplePhone implements Phone {
     

        @Override
        public void sendMsg() {
     
            System.out.println("apple phone send msg");
        }
    }

    class XiaomiPhone implements Phone {
     

        @Override
        public void sendMsg() {
     
            System.out.println("xiao mi send msg");
        }
    }

}

运行结果

apple phone send msg

这边小编为了方便就用内部类方式写了,是不是觉得非常简单啊。

框架源码中应用

简单工厂在日志框架中运用居多,包括dubbo,mybatis等,这边咱们举一个dubbo的日志工厂来讲一下。小编将最精简的代码放到下面。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

public class LoggerFactory {
     
    private static volatile LoggerAdapter LOGGER_ADAPTER;
    private static final ConcurrentMap<String, FailsafeLogger> LOGGERS = new ConcurrentHashMap();

    private LoggerFactory() {
     
    }
	//使用简单工厂,是不是其实框架也写很多if else代码
    static {
     
        String logger = System.getProperty("dubbo.application.logger");
        if ("slf4j".equals(logger)) {
     
            setLoggerAdapter((LoggerAdapter)(new Slf4jLoggerAdapter()));
        } else if ("jcl".equals(logger)) {
     
            setLoggerAdapter((LoggerAdapter)(new JclLoggerAdapter()));
        } else if ("log4j".equals(logger)) {
     
            setLoggerAdapter((LoggerAdapter)(new Log4jLoggerAdapter()));
        } else if ("jdk".equals(logger)) {
     
            setLoggerAdapter((LoggerAdapter)(new JdkLoggerAdapter()));
        } else {
     
            try {
     
                setLoggerAdapter((LoggerAdapter)(new Log4jLoggerAdapter()));
            } catch (Throwable var6) {
     
                try {
     
                    setLoggerAdapter((LoggerAdapter)(new Slf4jLoggerAdapter()));
                } catch (Throwable var5) {
     
                    try {
     
                        setLoggerAdapter((LoggerAdapter)(new JclLoggerAdapter()));
                    } catch (Throwable var4) {
     
                        setLoggerAdapter((LoggerAdapter)(new JdkLoggerAdapter()));
                    }
                }
            }
        }

    }
}

除了日志工厂还包括mybatis中的执行器创建它在configuration类中,它并不是工厂命名方式,如下面代码,依旧if和else。

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
     
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
     
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
     
      executor = new ReuseExecutor(this, transaction);
    } else {
     
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
     
      executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

当然上面两个例子中其实还用了其他设计模式。小伙伴想一下是哪些啊?

优缺点

优点

  1. 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
  2. 客户端无需知道所创建具体产品的类名,只需知道参数即可。
  3. 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。

缺点

  1. 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
  2. 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度。
  3. 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂。
  4. 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。

工厂方法

由于简单工厂有上述缺点,所以在简单工厂的基础上,为了其扩展性,咱们引入了工厂方法模式,他其实是将工厂继续抽象出来。看下器结构图

模式结构图

创建型模式之工厂模式以及对应框架用到的源码_第2张图片

代码示例

public class MethodFactory {
     

    public static void main(String[] args) {
     
        //这个因为是自己测试,时间是通过配置文件读取而来的。
        MyMethodFactory methodFactory = new MethodFactory().new AppleFactory();
        methodFactory.createPhone().sendMsg();

    }
    interface MyMethodFactory{
     
        public Phone createPhone();
    }

    class AppleFactory implements MyMethodFactory{
     

        @Override
        public Phone createPhone() {
     
            System.out.println("apple phone factory");
            return new ApplePhone();
        }
    }

    class XiaomiFactory implements MyMethodFactory{
     
        @Override
        public Phone createPhone() {
     
            System.out.println("xiao mi phone factory");
            return new XiaomiPhone();
        }
    }

    interface Phone {
     
        void sendMsg();
    }

    class ApplePhone implements Phone {
     

        @Override
        public void sendMsg() {
     
            System.out.println("apple phone send msg");
        }
    }

    class XiaomiPhone implements Phone {
     

        @Override
        public void sendMsg() {
     
            System.out.println("xiao mi send msg");
        }
    }

}

执行结果

apple phone factory
apple phone send msg

上面读取配置省略了,如果有兴趣可以点开参考文章中的链接。那边有配置文件读取示例。

框架源码中应用

工厂方法的工厂在源码中的咱们举一个dubbo的注册中心,dubbo注册中心有好多,最常用的是zookeeper,还有其他包括redis,multicast等等。咱们挑最重要的源码看一下啊

//工厂接口
@SPI("dubbo")
public interface RegistryFactory {
     

    /**
     * 连接注册中心.
     * 
     * 连接注册中心需处理契约:
* 1. 当设置check=false时表示不检查连接,否则在连接不上时抛出异常。
* 2. 支持URL上的username:password权限认证。
* 3. 支持backup=10.20.153.10备选注册中心集群地址。
* 4. 支持file=registry.cache本地磁盘文件缓存。
* 5. 支持timeout=1000请求超时设置。
* 6. 支持session=60000会话超时或过期设置。
* * @param url 注册中心地址,不允许为空 * @return 注册中心引用,总不返回空 */
@Adaptive({ "protocol"}) Registry getRegistry(URL url); } //抽象工厂 public abstract class AbstractRegistryFactory implements RegistryFactory { public Registry getRegistry(URL url) { url = url.setPath(RegistryService.class.getName()) .addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName()) .removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY); String key = url.toServiceString(); // 锁定注册中心获取过程,保证注册中心单一实例 LOCK.lock(); try { Registry registry = REGISTRIES.get(key); if (registry != null) { return registry; } //具体注册中心调到的方法 registry = createRegistry(url); if (registry == null) { throw new IllegalStateException("Can not create registry " + url); } REGISTRIES.put(key, registry); return registry; } finally { // 释放锁 LOCK.unlock(); } } //具体工厂所需要实现的类 protected abstract Registry createRegistry(URL url); } //以zookeeper为例 public class ZookeeperRegistryFactory extends AbstractRegistryFactory { private ZookeeperTransporter zookeeperTransporter; public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) { this.zookeeperTransporter = zookeeperTransporter; } public Registry createRegistry(URL url) { return new ZookeeperRegistry(url, zookeeperTransporter); } }

优缺点

优点

  1. 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
  2. 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
  3. 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。

缺点

  1. 类的个数容易过多,增加复杂度。
  2. 增加了系统的抽象性和理解难度。
  3. 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。

抽象工厂

讲到抽象工厂,首先上面工厂是一整套的,什么是一整套,就是比方说是手机,他生产出来就是一个手机。那假如说工厂是代加工的,屏幕是tcl或三星的,cpu是高通或天机的,摄像头是索尼的等等。然后不同品牌的手机需要的是一整个手机,需要的是将屏幕,cpu,摄像头等等拼装成的。那产品是不是工厂需要抽象生产一系列的产品,当然产品也是不同点。然后一系列的产品为一个品牌的手机。不知道小编讲清楚没有。接下来上模型结构图

模式结构图

创建型模式之工厂模式以及对应框架用到的源码_第3张图片

代码示例

这边小编简单的实现一个
工厂抽象

public interface PhoneFactory {
     
    Cpu createCpu();
    Camera createCamera();
    Screen createScreen();

    interface Cpu{
     
        void getCpuType();
    }
    interface Camera{
     
        void getCameraType();
    }
    interface Screen{
     
        void getScreenType();
    }
}

具体实现

public class AbstractFactory {
     
    public static void main(String[] args) {
     
    	//跟工厂方法一样,这个根据配置获得。测试简单创建对象
        PhoneFactory abstractFactory = new AbstractFactory().new XiaomiPhoneFactory();
        abstractFactory.createCamera().getCameraType();
    }

    class XiaomiPhoneFactory implements PhoneFactory{
     
        public XiaomiPhoneFactory(){
     
            System.out.println("xiao mi phone factory");
        }

        @Override
        public Cpu createCpu() {
     
            return new XiaomiCpu();
        }

        @Override
        public Camera createCamera() {
     
            return new XiaomiCamera();
        }

        @Override
        public Screen createScreen() {
     
            return new XiaomiScreen();
        }
    }

    class ApplePhoneFactory implements PhoneFactory{
     

        @Override
        public Cpu createCpu() {
     
            return new AppleCpu();
        }

        @Override
        public Camera createCamera() {
     
            return new AppleCamera();
        }

        @Override
        public Screen createScreen() {
     
            return new AppleScreen();
        }
    }

    class XiaomiCpu implements PhoneFactory.Cpu{
     
        @Override
        public void getCpuType() {
     
            System.out.println("xiao mi Cpu");
        }
    }

    class XiaomiScreen implements PhoneFactory.Screen{
     
        @Override
        public void getScreenType() {
     
            System.out.println("xiao mi Screen");
        }
    }

    class XiaomiCamera implements PhoneFactory.Camera{
     
        @Override
        public void getCameraType() {
     
            System.out.println("xiao mi Camera");
        }
    }

    class AppleCpu implements PhoneFactory.Cpu{
     
        @Override
        public void getCpuType() {
     
            System.out.println("apple cpu");
        }
    }

    class AppleScreen implements PhoneFactory.Screen{
     
        @Override
        public void getScreenType() {
     
            System.out.println("apple Screen");
        }
    }

    class AppleCamera implements PhoneFactory.Camera{
     
        @Override
        public void getCameraType() {
     
            System.out.println("apple Camera");
        }
    }
}

框架源码中应用

暂时小编并未找到,可能对于一个大型平台中有应用此工厂模式但是没有开源的。

优缺点

优点

  1. 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
  2. 当需要产品族时,抽象工厂可以保证客户端始终只使用同一个产品的产品组。
  3. 抽象工厂增强了程序的可扩展性,当增加一个新的产品族时,不需要修改原代码,满足开闭原则。
  4. 同时包含了上面工厂的优点

缺点

  1. 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度。

总结

讲到这儿,今天的工厂模式就已经结束了,不知道大家更喜欢用那种方式呢,小编觉得自己水平有限,用用简单的就行了,毕竟在咱们实际的业务中,已经够用,并且后来的小伙伴们看代码时能够更加清晰明了。小伙伴们觉得呢,希望给大家带来帮助啊。

感谢与参考

感谢源码阅读网,鲁班大叔的讲解及案例
本文借鉴了相关文章
简单工厂 :http://c.biancheng.net/view/8385.html.
工厂方法: http://c.biancheng.net/view/1348.html.
抽象工厂: http://c.biancheng.net/view/1351.html.

你可能感兴趣的:(设计模式,#,创建型模式,设计模式,java)