设计模式-简单工厂

生活中,原始社会自给自足(没有工厂),农耕社会小作坊(简单工厂,民间酒坊),工业革命流水线(工厂方法,自产自销),现代产业链代工厂(抽象工厂,富士康)。人们不再关心产品时如何生产的,他们只需要知道自己要什么,工厂就会给什么。至于怎么生产,那是工厂的事情。

1. 概述

在日常开发中,凡是需要生成复杂对象的地方,都可以尝试考虑使用工厂模式来代替。简单工厂模式有一个具体的工厂类,一个产品的抽象类或者接口,用来规范产品。将所有的具体产品的生产都罗列到工厂中。

1.1. 优点

  • 很方便的创建出相应的产品。工厂和产品的职责区分明确;
  • 客户端无需知道所创建具体产品的类名,只需知道参数即可;
  • 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类;

1.2. 缺点

  • 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

1.3. 使用场景

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

2. 代码实例

在做 TCP 服务数据解析时,我们通常需要将接收到的数据转化为不同格式的数据报文。我们抽象处理器来处理此类业务。

package com.skystep.设计模式.工厂模式.简单工厂;

public interface Handler {
    // 协议转换 将接受到的报文转化为另一种格式的报文
    void change();
}

现在我们试着写一个转化为JSON格式的处理。

package com.skystep.设计模式.工厂模式.简单工厂;

public class JsonHandler implements Handler {
    @Override
    public void change() {
        // 进行json格式解析
        System.out.println("JSON-DATA");
    }
}

我们也可以实现一个xml格式的处理器。

package com.skystep.设计模式.工厂模式.简单工厂;

public class XmlHandler implements Handler {
    @Override
    public void change() {
        // 进行json格式解析
        System.out.println("XML-DATA");
    }
}

当然我们还可以增加一个默认的处理器,作为报文的默认处理器。


package com.skystep.设计模式.工厂模式.简单工厂;

public class DefaultHandler implements Handler {
    @Override
    public void change() {
        // 进行json格式解析
        System.out.println("DEFAULT-DATA");
    }
}

实现一个简单工厂,把所有的处理的生产罗列到工厂类中。


package com.skystep.设计模式.工厂模式.简单工厂;

public class HandlerFactory {

    public static Handler getHandler(HandlerType handlerType) {
        Handler ret;
        if (handlerType == HandlerType.JSON_HANDLER) {
            ret = new JsonHandler();
        } else if (handlerType == HandlerType.XML_HANDLER) {
            ret = new XmlHandler();
        } else {
            ret = new DefaultHandler();
        }
        return ret;
    }
}

package com.skystep.设计模式.工厂模式.简单工厂;

public enum HandlerType {
    JSON_HANDLER(1, "JSON_HANDLER"),
    XML_HANDLER(2, "XML_HANDLER"),
    DEFAULT_HANDLER(0, "DEFAULT_HANDLER");

    private Integer code;
    private String desc;

    HandlerType(Integer code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public Integer getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }
}


客户端模拟获取处理器。


package com.skystep.设计模式.工厂模式.简单工厂;

public class Client {
    public static void main(String[] args) {
        Handler jsonHandler = HandlerFactory.getHandler(HandlerType.JSON_HANDLER);
        jsonHandler.change();
        Handler xmlHandler = HandlerFactory.getHandler(HandlerType.XML_HANDLER);
        xmlHandler.change();
    }
}

JSON-DATA
XML-DATA

Process finished with exit code 0

3. 扩展解读

3.1. SpringBoot 项目中使用 简单工厂

在实际项目中,我们通常使用 SpringBoot 进行开发,结合 IOC 机制也可以使用简单工厂达到简化产品生产,同时符合开闭原则。

规范处理器的行为,并且要求每类处理器都需要增加一个id,相当于产品的型号。让客户端方便指定生产哪个型号的处理器。

package com.skystep.aspect.sevice;

public interface Handler {
    // 协议转换 将接受到的报文转化为另一种格式的报文
    String change(String data);

    // 获取处理器的id,相当于产品的型号
    Integer getId();
}

实现JSON处理器,并且使用 @Component 注解注册为 IOC 容器中的一个实例。


package com.skystep.aspect.sevice;

import org.springframework.stereotype.Component;

@Component
public class JsonHandler implements Handler {
    @Override
    public String change(String data) {
        // 进行json格式解析
        System.out.println("JSON-DATA");
        return "JSON-DATA:" + data;
    }

    @Override
    public Integer getId() {
        return HandlerType.JSON_HANDLER.getCode();
    }
}

实现XML处理器,并且使用 @Component 注解注册为 IOC 容器中的一个实例。


package com.skystep.aspect.sevice;

import org.springframework.stereotype.Component;

@Component
public class XmlHandler implements Handler {
    @Override
    public String change(String data) {
        // 进行json格式解析
        System.out.println("XML-DATA");
        return "XML-DATA:" + data;
    }

    @Override
    public Integer getId() {
        return HandlerType.XML_HANDLER.getCode();
    }
}


实现默认处理器,并且使用 @Component 注解注册为 IOC 容器中的一个实例。


package com.skystep.aspect.sevice;

import org.springframework.stereotype.Component;

@Component
public class DefaultHandler implements Handler {
    @Override
    public String change(String data) {
        // 进行json格式解析
        System.out.println("DEFAULT-DATA");
        return "DEFAULT-DATA:" + data;
    }

    @Override
    public Integer getId() {
        return HandlerType.DEFAULT_HANDLER.getCode();
    }
}


实现一个简单工厂,在工厂中维护一个 map,将型号和处理器对应起来,存储到 map,提供统一的获取方法。


package com.skystep.aspect.sevice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

@Component
public class HandlerFactory {
    @Autowired
    private ApplicationContext ac;

    public static Map<Integer, Handler> handers = new HashMap<>();

    @PostConstruct
    public void init() {
        Map<String, Handler> settings = ac.getBeansOfType(Handler.class);
        for (Map.Entry<String, Handler> el : settings.entrySet()) {
            Handler handler = el.getValue();
            Integer id = handler.getId();
            handers.put(id, handler);
        }
    }

    public Handler getHandler(Integer id) {
        return handers.get(id) == null ?
                handers.get(HandlerType.DEFAULT_HANDLER.getCode()) : handers.get(id);
    }
}

实现一个控制器,供客户端进行调用,可以输入需要转化的字符串和转化的的格式(JSON/XML等)。

package com.skystep.aspect.controller;


import com.skystep.aspect.sevice.Handler;
import com.skystep.aspect.sevice.HandlerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class HelloController {

    @Autowired
    HandlerFactory handlerFactory;

    @RequestMapping("/handler")
    public String change(@RequestParam String data, @RequestParam Integer type) {
        Handler handler = handlerFactory.getHandler(type);
        return handler.change(data);
    }
}

在这里,我们巧妙使用简单工厂和IOC思想,使用 getBeanByType 将实现 Handler 接口的实例汇总到工厂中,又提供了获取方法。如此一来,后续的要实现不同的数据转化,我们只需实现另外一个处理类,将类注册到IOC容器中即可,其他的业务逻辑代码都不需要改变,基本上达到开闭原则。

posted @ 2021-11-21 15:06  yaomianwei  阅读(13)  评论(0编辑  收藏  举报