1. 程式人生 > >工廠方法模式應用場景

工廠方法模式應用場景

工廠方法模式

      工廠方法(Factory Method)模式的意義是定義一個建立產品物件的工廠介面,將實際建立工作推遲到子類當中。核心工廠類不再負責產品的建立,這樣核心類成為一個抽象工廠角色,僅負責具體工廠子類必須實現的介面,這樣進一步抽象化的好處是使得工廠方法模式可以使系統在不修改具體工廠角色的情況下引進新的產品。

     工廠方法模式是簡單工廠模式的衍生,解決了許多簡單工廠模式的問題。首先完全實現‘開-閉原則’,實現了可擴充套件。其次更復雜的層次結構,可以應用於產品結果複雜的場合。

      首先,我們先介紹簡單工廠模式。

      簡單工廠模式是屬於建立型模式,又叫做靜態工廠方法(Static Factory Method)模式,但不屬於23種GOF設計模式之一。簡單工廠模式是由一個工廠物件決定創建出哪一種產品類的例項。簡單工廠模式是工廠模式家族中最簡單實用的模式,可以理解為是不同工廠模式的一個特殊實現。

       下面,我將由具體的例項一步步的引出為什麼要用工廠方法模式,以及工廠方法模式解決了哪些問題。

       想象一下,如果讓我們自己實現一個簡單的像 log4j 那樣的日誌框架該怎麼設計呢?

我們可能這樣做,但這樣做的壞處是什麼?

public class Log1 {
    public static void debug(String message){
        System.out.println(message);
    }
}
public class Client2 {
    Logger logger= LoggerFactory.getLogger(Config.LOG_TYPE);
    public void begin(){
        logger.debug("log");
    }
}

這樣做的壞處就是

有一天,我們想要把我們的應用改為一個更好日誌框架,我們蒙了,為什麼呢?

因為像                                                   

Log1 log1=new Log1();

這樣的程式碼在每個類裡面都有一個,我們要每一個都要更改,麻煩不說,還易出錯。

於是我們做了如下改進。簡單工廠模式登場了。 

public class LoggerFactory {
    public static Logger getLogger(String logType){
        if("Log1".equals(logType)){
            return new Log1();
        }
        if("Log2".equals(logType)){
            return new Log2();
        }
        return null;
    }
}
public class Client2 {
    Logger logger= LoggerFactory.getLogger(Config.LOG_TYPE);
    public void begin(){
        logger.debug("log");
    }
}  

這樣,我們只需改下配置中的日誌型別就可以實現兩種日誌間的無縫切換,看起來一切完美。

簡單工廠模式將日誌物件的例項化推遲到工廠中,實現了應用和日誌物件的例項化的解耦。

但是,簡單工廠模式有什麼不足呢?

工廠方法模式又改進了簡單工廠模式的哪些缺點呢?

現在,我們又覺得原先的日誌框架功能不太好用,我們又想開發一個新的日誌框架了。

於是我們又加了一個if else 。如果以後我們又想再加呢?我們還得再寫一個if else 。

像下面這樣

public class LoggerFactory {
    public static Logger getLogger(String logType){
        if("Log1".equals(logType)){
            return new Log1();
        }
        if("Log2".equals(logType)){
            return new Log2();
        }
        if("Log3".equals(logType)){
            return new Log3();
        }
        return null;
    }
}

我們已經發現問題了,這樣做違反了開閉原則。

於是。。。。。。工廠方法模式登場了

於是我們進一步改進我們的框架,採用工廠方法模式。

public class LoggerFactory {

    private static IFactory iFactory;
    
    public static Logger getLogger(){
        return iFactory.getLogger();
    }
}
public interface IFactory {
    Logger getLogger();
}

public class Log1Factory implements IFactory {

    @Override
    public Logger getLogger() {
        return new Log1();
    }
}

這樣,當以後我們再有新的日誌框架時

只要這個新的日誌框架符合我們的介面定義,實現了Ifactory 介面。我們就只需要為LoggerFactroy 的ifactory 注入這個新的工廠就行了。

注入方式可以是構造方法注入,setter 注入或者讓 Spring 幫我們注入。

不錯,self4j 就是這麼一個日誌介面的定義。Log4j2 和Logback 都實現了self4j 的介面,所以我們就可以開開心心的在Log4j2 和Logback 以及以後可能出的任何實現self4j 介面的日誌框架之間自由切換了。

當然,他們的實現比我們這個簡單的樣例要複雜的多。

而且他們注入工廠是自動掃描工程中實現 self4j介面的實現類來實現,所以只要我們引入相關jar 包就行啦。