每日设计模式——工厂模式之二(工厂方法模式)

简单工厂模式负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护 。虽然最后我们改进了简单工厂模式,即使增加产品类也不需要再去修改工厂类,但是这也增加了客户端代码的复杂度(客户端需要知道创建哪个类的实例)。

工厂方法模式

工厂方法模式定义一个用于创建对象的接口,让子类去决定实例化哪一个类,工厂方法模式使一个类的实例化延迟到其子类。

下面考虑一个具体的应用场景:

实现一个导出数据的应用框架,来让客户选择数据的导出方式(如导出为json文件,xml文件),并真正的执行数据的导出。

通常情况下,在不使用任何设计模式的情况下,代码通常如下:

public class NonFactory {
    public static void main(String[] args) {
        ExportOperator operator = new ExportOperator();
        operator.export(1, "gaga");
        operator.export(2, "hahah");
        operator.export(3, "dadaa");
    }
}

interface DataExportApi {
    public void export(String data);
}

class DataExportJson implements DataExportApi {

    public void export(String data) {
        System.out.println("导出数据到json文件");
    }
}

class DataExportXml implements DataExportApi {

    public void export(String data) {
        System.out.println("导出数据到xml文件");
    }
}

class ExportOperator {
    DataExportApi api = null;

    public void export(int type, String data) {
        if (type == 1) {
            api = new DataExportJson();
        } else if (type == 2) {
            api = new DataExportXml();
        }
        api.export("data");
    }
}

乍一看,这个代码也没问题啊,也能实现需要的功能。但是,万一客户需要增加新的导出格式,那我们就需要修改ExportOperator类了(违反了修改关闭原则),并且这种传参数决定创建哪个子类的方式也存在很大的隐患,你永远无法预料客户给你传递的参数是什么样的,比如说咱们测试代码里边传递的参数:  operator.export(3, "dadaa");就是不合法的,可能会造成程序无法正常工作。那么如何解决这个问题呢???答案是使用工厂方法模式,将实例的创建交给子类,代码如下所示:

public class Factory {
    public static void main(String[] args) {
        Export_Operator operator = new ExportDataXmlOperator();
        operator.export("hahah");
        operator = new ExportDataJsonOperator();
        operator.export("");
    }
}

abstract class Export_Operator {

    public void export(String data) {
        DataExport_Api api = factoryMethod();
        api.export(data);
    }

    public abstract DataExport_Api factoryMethod();
}

abstract class DataExport_Api {
    public abstract void export(String data);
}

class ExportDataXmlOperator extends Export_Operator {

    public DataExport_Api factoryMethod() {
        return new ExportDataXml();
    }
}

class ExportDataJsonOperator extends Export_Operator {

    public DataExport_Api factoryMethod() {
        return new ExportDataJson();
    }
}


class ExportDataXml extends DataExport_Api {

    public void export(String data) {
        System.out.println("导出到xml文件");
    }
}

class ExportDataJson extends DataExport_Api {

    public void export(String data) {
        System.out.println("导出到json文件");
    }
}

其类图结构如下所示:

这样一来的话,当我们需要增加新的数据导出格式的时候,只需要增加一个DataExport_Api的子类以及对应的Export_Operator 的子类即可,实现了对修改关闭。但是随着子类的增加,工厂类也增加,类的数量会越来越多,造成类膨胀。其实,对简单工厂的改进办法也同样可以用来改进工厂方法模式,下面是改进的代码:

public class Factory {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Export_Operator operator = new ExportDataOperator();
        operator.export("hahah", ExportDataXml.class);
        operator.export("", ExportDataJson.class);
    }
}

abstract class Export_Operator {
    public void export(String data, Class<? extends DataExport_Api> clzz) throws InstantiationException, IllegalAccessException {
        DataExport_Api api = factoryMethod(clzz);
        api.export(data);
    }

    public abstract DataExport_Api factoryMethod(Class<? extends DataExport_Api> clzz) throws IllegalAccessException, InstantiationException;
}

abstract class DataExport_Api {
    public abstract void export(String data);
}

class ExportDataOperator extends Export_Operator {
    public DataExport_Api factoryMethod(Class<? extends DataExport_Api> clzz) throws IllegalAccessException, InstantiationException {
        return clzz.newInstance();
    }
}


class ExportDataXml extends DataExport_Api {

    public void export(String data) {
        System.out.println("导出到xml文件");
    }
}

class ExportDataJson extends DataExport_Api {

    public void export(String data) {
        System.out.println("导出到json文件");
    }
}

工厂方法模式的本质是:延迟到子类来选择实现

和简单工厂一样,上述改进也不可避免的会造成调用复杂度的增加,但是却换来了工厂类的减少。具体使用过程中可以衡量对比一下再做取舍。

工厂方法模式使用场景

工厂方法模式new一个对象的替代品,所以在需要生成对象的地方都可以使用,但是需要考虑是否有必要增加一个工厂类来增加代码的复杂度。

其次,需要灵活的可扩展的框架时,可以考虑采用工厂模式方法。例如实现一个连接邮件服务器的框架(可供选择的网络协议有:POP3,IMAP,HTTP),可能需要扩展一个webservice接口等。

工厂模式的优点

1. 良好的封装性,代码结构清晰。如果一个调用者需要一个具体的产品对象,只需要知道这个产品的工厂是谁就行了,不用知道创建对象的具体过程。

2.扩展性好。在增加产品类的情况下,只需要扩展一个工厂类就可以“拥抱变化”。

3.屏蔽产品类。这一点很重要,产品类的具体实现如何变化,调用者都不需要关心,它只需要关心产品的接口,只要接口不变,系统中的上层模块就不需要发生变化。因为产品类的实例化工作是由工厂类负责的,一个产品对象具体由哪一个产品类生成是由工厂类决定的。

4.工厂模式是典型的解耦框架。高层模块只需要知道产品的抽象类,其他的实现类都不需要关心。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值