• 【设计模式】简单工厂


    简单工厂模式

    严格的说,简单工厂模式并不属于 23 中设计模式,不过我浏览了几本与设计模式相关的术后,发现都提及了该知识点,可能作者的目的是为了让我们能循序渐进地理解后面的工厂方法、抽象工厂。总之,这个模式还是一个很值得去理解的模式。

    问题的引入

    在设计原则中有这么一句话——“要面向接口编程,而不要面向实现编程”。不过我们一直使用 new 关键字创建对象,这好像有悖这一原则。

    接口的思想是封装隔离,这里的封装指的是“对被隔离体的行为的封装”,或者说是“对被隔离体职责的封装”;所以面向接口编程,可以免去将来系统发生的一系列修改。假如是面向接口编程,那么今后代码发生改变时,可以通过多态,让任何新的类实现该接口。但是如果我们在代码中将接口引向具体类,那么情况就不是那么乐观了,因为一旦要加入新的具体类,你就必须改变代码。用代码来说明或许会简明了当些

    首先我们定义一个接口

    public interface Utils {
        /**
        * 定义一个行为
        */
        void log(String s);
    }
    

    现在我们再定义一个类来实现这个接口

    public class StringUtils implement Utils {
        public void log(String s) {
            sout("StringUtils Implement:" + s);
        }
    }
    

    那么此时我们会怎么调用这个接口中的行为呢?使用接口的实现类?

    public class Test {
        public static void main(String[] args) {
            Utils utils = new StringUtils();
            utils.log("hello world!");
        }
    }
    

    这样看起来这段代码好像没什么问题。但是,接口的思想是“封装隔离”,所以实现类 StringUtils 应该是被接口 Utils 封装并同 Test 离开的,换而言之就是 Test 类不应该知道 Utils 的实现类是 StringUtils。以上代码并不符合DIP(Dependence Inversion Principle)原则,所以在这里,我们就需要有一个简单的方法,当我传递参数调用它的时候,就可以返回一个我要的具体实现对象给我。这就是将要介绍的简单工厂模式。

    实现思路

    简单工厂的定义
    提供一个创建对象实例的功能,而无需关心其具体实现。被创建实例的类型可以是接口、抽象类、也可以是具体的类。

    现在在之前代码的基础上,对 Utils 新增加一个实现类

    public class LogUtils implement Utils {
        public void log(String s) {
            sout("LogUtils Implement:" + s);
        }
    }
    

    接下来就可以创建一个简单工厂了,实例代码如下:

    public class Factory {
    
        // 具体创建 Utils 对象的方法
        public static Utils createUtils(String condition) {
            Utils utils = null;
            if (condition.equals("string")) {
                utils = new StringUtils();
            } 
            else if(condition.equals("log")) {
                utils = new LogUtils();
            }
            return utils;
        }
    }
    

    现在我们就可以使简单工厂方法来得到一个对象了

    public class Test {
    
        public static void main(String[] args) {
            Utils utils = Factory.createUtils("String");
            utils.log("hello java");
        }
    }
    

    可配置的简单工厂

    上面代码就是简单工厂的具体实现了,也达到了我们想要的封装和解耦的目的,但是还有一个问题,就是要怎么样添加一个新的实现类呢?假如我现在对 Utils 接口还有一个新的实现类 DateUtils,那么要怎么样将其添加到工厂中呢?

    最简单的方式当然是在工厂类的方法中添加新的代码块了

    else if(confition.equals("date") {
        utils = new DateUtils();
    }
    

    不过每增加一个新的实现类,就改动一次工厂类,这样的实现方式不是很妥当,所以就要引入其他的方式了,例如通过配置文件来实现添加新的实现类

    首先你需要定义一个配置文件“Factory.properties”,然后在配置类中定义你要的实现类

    ImplClass=com.java.factory.DateUtils
    

    如果添加了实现类,修改配置文件中的配置即可,就不用去修改代码而从新编译了。

    接下来定义新的工厂类的实现

    public class Factory() {
        
        public static Utils createUtils() throws Exception {
           
            Properties p = new Properties();
            InputStream in = Factory.class.getResourceAsStream("Factory.properties");
            p.load(in);
            
            Utils utils = (Utils)Class.forName(p.getProperty("ImplClass").newInstance())
            
            return utils;
        }
        
    }
    

    emmmm,这样实现应该可以解决上面的问题了。不过这里还有更好的实现方式,就是采用Ioc/DI的方式来实现。

    谈一谈优劣

    • 优点:简单工厂帮助实现了封装隔离,使外部调用组件能真正实现面向接口编程,同时也实现了程序间的解耦。
    • 劣势:加重了程序员理解代码的成本,如果工厂需要通过参数来选择实现类,那么就还需要让程序员去理解每个参数所代表的含义。
  • 相关阅读:
    Mysql 常用函数(34)- week 函数
    Mysql 常用函数(33)- dayofmonth 函数
    Mysql 常用函数(32)- dayofyear 函数
    Mysql 常用函数(31)- dayofweek 函数
    Mysql 常用函数(30)- month 函数
    Mysql 常用函数(29)- sysdate 函数
    Mysql 常用函数(28)- datediff 函数
    Mysql 常用函数(27)- now 函数
    Azure Messaging-ServiceBus Messaging消息队列技术系列1-基本概念和架构
    Oracle 12c In Memory Option初探
  • 原文地址:https://www.cnblogs.com/jojop/p/11220707.html
Copyright © 2020-2023  润新知