设计模式之工厂模式

概念

工厂模式分三种:简单工厂模式、工厂方法模式、抽象工厂模式。

  • 简单工厂工厂模式:属于类的创新型模式,又叫静态工厂方法模式,是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类或实现共同的接口。
  • 工厂方法模式(Factory Method):定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
  • 抽象工厂模式(Abstract Factory Pattern):是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

代码示例

简单工厂模式

public class CertTypeFactory {
    public static CertTypeProcess getCertTypeProcess(String code) {
        CertTypeProcess process = null;
        if ("AUTH".equals(code)) {
            process = new AuthCertTypeProcess();
        } esle if ("QC".equals(code)) {
            process = new QcCertTypeProcess();
        } else if ("ACCEPT".equals(code)) {
            process = new AcceptCertTypeProcess();
        } else {
            process = new QualifyCertTypeProcess();
        }
        return process;
    }
}

在上面的代码实现中,我们每次调用CertTypeFactory的getCertTypeProcess()的时候,都要创建一个新的process。实际上,如果process可以复用,为了节省内存和对象创建的时间,我们可以将process事先创建好缓存起来。当调用getCertTypeProcess()函数的时候,我们从缓存中取出process对象直接使用。

这有点类似单例模式和简单工厂模式的结合,具体的代码实现如下所示。在接下来的讲解中,我们把上一种实现方法叫作简单工厂模式的第一种实现方法,把下面这种实现方法叫作简单工厂模式的第二种实现方法。

public class CertTypeFactory {

    private static Map<String, CertTypeProcess> CERT_TYPE_PROCESS_MAP = new HashMap<>(8);

    static {
        init();
    }

    private static void init() {
        CERT_TYPE_PROCESS_MAP.put(CertTypeEnums.AUTH.name().toUpperCase(), new AuthCertTypeProcess());
        CERT_TYPE_PROCESS_MAP.put(CertTypeEnums.QC.name().toUpperCase(), new QcCertTypeProcess());
        CERT_TYPE_PROCESS_MAP.put(CertTypeEnums.ACCEPT.name().toUpperCase(), new AcceptCertTypeProcess());
        CERT_TYPE_PROCESS_MAP.put(CertTypeEnums.QUALIFY.name().toUpperCase(), new QualifyCertTypeProcess());
    }

    public static CertTypeProcess getCertTypeProcess(String code) {
        RequirementTemplateTreeNodeModel firstTreeNodeByValue
            = CertAuthTypeClient.getCertTypeFirstTreeNodeByValue(code);
        return CERT_TYPE_PROCESS_MAP.get(firstTreeNodeByValue.getValue());
    }
}

对于上面两种简单工厂模式的实现方法,如果我们要添加新的process,那势必要改动到CertTypeFactory的代码,那这是不是违反开闭原则呢?实际上,如果不是需要频繁地添加新的process,只是偶尔修改一下CertTypeFactory代码,稍微不符合开闭原则,也是完全可以接受的。

如果完全不能接受修改Factory中的代码的话,其实也是有实现的方法的。可以将process实现共同的接口然后扫描该接口,获取所有实现该接口的类,通过反射实例化该类并将实例存储在map中。具体实现请看一下代码:

引入依赖:

        <dependency>
            <groupId>org.reflections</groupId>
            <artifactId>reflections</artifactId>
            <version>0.9.11</version>
        </dependency>

编写process接口及其实现:

public interface CertTypeProcess {

    /**
     * 执行证书类型参数处理逻辑
     * @param param
     */
    void run(CertParam param);
    /**
    * 子类名称
    */
    String getName();
}
实现一
public class AuthCertTypeProcess implements CertTypeProcess {
    @Override
    public String getName() {
        return "authCertTypeProcess";
    }
    @Override
    public void run(CertParam param) {
        RequirementTemplateTreeNodeModel firstTreeNodeByValue
            = CertAuthTypeClient.getCertTypeFirstTreeNodeByValue(param.getCertCategoryValue());
        param.setCertType(Integer.parseInt(firstTreeNodeByValue.getType()));
        param.setCertCategory(
            Integer.parseInt(CertAuthTypeClient.getCertTypeTreeNodeByValue(param.getCertCategoryValue()).getType()));
        param.setCertAuthType(param.getCertCategoryValue());
    }
}
实现二
public class QcCertTypeProcess implements CertTypeProcess{
    @Override
    public String getName() {
        return "qcCertTypeProcess";
    }
    @Override
    public void run(CertParam param) {
        RequirementTemplateTreeNodeModel firstTreeNodeByValue
            = CertAuthTypeClient.getCertTypeFirstTreeNodeByValue(param.getCertCategoryValue());
        param.setCertType(Integer.parseInt(firstTreeNodeByValue.getType()));
        param.setCertCategory(
            Integer.parseInt(CertAuthTypeClient.getCertTypeTreeNodeByValue(param.getCertCategoryValue()).getType()));
        param.setCertAuthType(param.getCertCategoryValue());
    }
}
实现三
public class AcceptCertTypeProcess implements  CertTypeProcess{
    @Override
    public String getName() {
        return "acceptCertTypeProcess";
    }
    @Override
    public void run(CertParam param) {
        RequirementTemplateTreeNodeModel firstTreeNodeByValue
            = CertAuthTypeClient.getCertTypeFirstTreeNodeByValue(param.getCertCategoryValue());
        param.setCertType(Integer.parseInt(firstTreeNodeByValue.getType()));
        param.setCertAuthType(param.getCertCategoryValue());
    }
}
实现四
public class QualifyCertTypeProcess implements CertTypeProcess{
    @Override
    public String getName() {
        return "acceptCertTypeProcess";
    }
    @Override
    public void run(CertParam param) {
        RequirementTemplateTreeNodeModel firstTreeNodeByValue
            = CertAuthTypeClient.getCertTypeFirstTreeNodeByValue(param.getCertCategoryValue());
        param.setCertType(Integer.parseInt(firstTreeNodeByValue.getType()));
        param.setCertAuthType(param.getCertCategoryValue());
    }
}

工厂类进行实例化CertTypeProcess的实现

public class CertTypeFactory {

    private static Map<String, CertTypeProcess> CERT_TYPE_PROCESS_MAP = new HashMap<>(8);
    private static Set<String> set = Sets.newHashSet("com.fxq.test.reflections");
    static {
        init();
    }

    private static void init() {
        ConfigurationBuilder cb = ConfigurationBuilder.build(set, new SubTypesScanner(true),
                new TypeAnnotationsScanner(),
                new FieldAnnotationsScanner());
        Reflections reflections = new Reflections(cb);
        Set<Class<? extends CertTypeProcess>> typesOf = reflections.getSubTypesOf(CertTypeProcess.class);
        for (Class cls : typesOf) {
            if (CertTypeProcess.class.isAssignableFrom(cls)) {
                CertTypeProcess newInstance = ClassLoaderUtil.getInstants(cls);
                map.put(newInstance.getName(), newInstance);
            }
        }
        
    }

    public static CertTypeProcess getCertTypeProcessByName(String name) {
        return CERT_TYPE_PROCESS_MAP.get(name);
    }
}

ClassLoaderUtil

public class ClassLoaderUtil {
    public static <T> T getInstants(Class cl) {
        try {
            return (T)cl.newInstance();
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }
}

以上代码实例可以看出当你新增process时完全不需要对工厂类CertTypeFactory进行修改,只需要将新增的process实现CertTypeProcess接口,如果你实现的process拥有特殊逻辑,并且其他的process不会用到,那你可以在实现一层接口,使之实现CertTypeProcess接口。

简单工厂模式代码简单,虽有多处if分支且违背开闭原则,但扩展性和可读性尚可,这样的代码在大多数情况下并无问题。

工厂方法模式

工厂方法如下图:

CertTypeProcess相关类参考简单工厂模式。

工厂类相关:

public interface IFactory {
    CertTypeProcess getCertTypeProcess();
}

public class AuthCertTypeProcessFactory implements IFactory{
    @Override
    public CertTypeProcess getCertTypeProcess() {
        return new AuthCertTypeProcess();
    }
}

public class QcCertTypeProcessFactory implements IFactory{
    @Override
    public CertTypeProcess getCertTypeProcess() {
        return new QcCertTypeProcess();
    }
}

public class AcceptCertTypeProcessFactory implements IFactory{
    @Override
    public CertTypeProcess getCertTypeProcess() {
        return new AcceptCertTypeProcess();
    }
}
public class QualifyCertTypeProcessFactory implements IFactory{
    @Override
    public CertTypeProcess getCertTypeProcess() {
        return new QualifyCertTypeProcess();
    }
}

但是如果通过这种方式,必须先获取具体的工厂类型在实例化出process,又像简单工厂的第一种情况,分支较多了。我们可以在采用简单工厂的第二种方式给工厂类型在封装一个工厂类。

public class CertTypeFactory {

    private static Map<String, IFactory> CERT_TYPE_PROCESS_FACTORY_MAP = new HashMap<>(8);

    static {
        init();
    }

    private static void init() {
        CERT_TYPE_PROCESS_FACTORY_MAP.put(CertTypeEnums.AUTH.name().toUpperCase(), new AuthCertTypeProcessFactory());
        CERT_TYPE_PROCESS_FACTORY_MAP.put(CertTypeEnums.QC.name().toUpperCase(), new QcCertTypeProcessFactory());
        CERT_TYPE_PROCESS_FACTORY_MAP.put(CertTypeEnums.ACCEPT.name().toUpperCase(), new AcceptCertTypeProcessFactory());
        CERT_TYPE_PROCESS_FACTORY_MAP.put(CertTypeEnums.QUALIFY.name().toUpperCase(), new QualifyCertTypeProcessFactory());
    }

    public static IFactory getCertTypeProcessFactory(String code) {
        return CERT_TYPE_PROCESS_FACTORY_MAP.get(code);
    }
}

什么时候使用工厂方法

工厂方法模式通过不同的工厂创建不同的对象,每个对象都有自己的工厂来创建。当对象的创建过程比较复杂,需要组合其他类对象做各种初始化操作时,推荐使用工厂方法模式。

抽象工厂模式

在简单工厂和工厂方法中,类只有一种分类方式。但是我们想想一下如果process的选择不只依赖传入的code,同时也可能会依赖其他的条件,比如处理一个param,根据不同的条件可能需要AuthCertTypeProcess和QcCertTypeProcess两种。

代码实例:

public class AuthOrQcCertTypeProcessFactory implements IFactory{
    @Override
    public CertTypeProcess getCertTypeProcess(String type) {
        if ("1".equals(type)) {
            return new AuthCertTypeProcess();
        } else  if ("2".equals(type)) {
            return new AQcCertTypeProcess();
        }
    }
}

public class AcceptOrQualifyCertTypeProcessFactory implements IFactory{
    @Override
    public CertTypeProcess getCertTypeProcess(String type) {
        if ("1".equals(type)) {
            return new AcceptCertTypeProcess();
        } else  if ("2".equals(type)) {
            return new QualifyCertTypeProcess();
        }
    }
}

在抽象工厂模式中,工厂不仅可以创建一种对象,还可创建一组对象。是用来解决产品簇的问题,而不是解决调用方的开闭原则的问题。

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值