開發與維運

反射與工廠設計模式 | 帶你學《Java語言高級特性》之八十三

上一篇:反射實例化對象 | 帶你學《Java語言高級特性》之八十二
【本節目標】
通過案例逐步掌握工廠設計模式,通過工廠類獲取指定接口的實例化對象。

反射與工廠設計模式

如果要想進行對象的實例化處理,除了可以使用關鍵字new之外,還可以使用反射機制來完成,於是此時一定會思考一個問題:為什麼要提供有一個反射的實例化?那麼到底是使用關鍵字new,還是使用反射呢?

如果要想更好的理解此類問題,最好的解決方案就是通過工廠設計模式來解決。

工廠模式的最大特點:客戶端的程序類不直接牽扯到對象的實例化管理,只與接口發生關聯,通過工廠類獲取指定接口的實例化對象。

範例:傳統的工廠設計模式

interface IMessage{
    public void send();  //消息發送
}
class NetMessage implements IMessage{
    public void send() {
        System.out.println("【網絡消息發送】www.mldn.cn");
    }
}
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
            IMessage msg = new NetMessage();  //如果直接實例化則一定會有耦合問題
    }
}

在實際的開發中,接口的主要作用是為不同層提供有一個操作的標準。但是如果此時直接將一個子類設置為接口實例化操作,那麼一定會有耦合問題,所以使用了工廠設計模式來解決此問題。
範例:利用工廠設計模式解決

public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        IMessage msg = Factory.getInstance("netmessage");
        msg.send();   //【網絡消息發送】www.mldn.cn
    }
}
interface IMessage{
    void send();  //消息發送
}
class NetMessage implements IMessage{
    public void send() {
        System.out.println("【網絡消息發送】www.mldn.cn");
    }
}
class Factory{
    private Factory(){}  //沒有產生實例化對象的意義,所以構造方法私有化
    public static IMessage getInstance(String className){
        if("netmessage".equalsIgnoreCase(className)){
            return new NetMessage();
        }
        return null;
    }
}

image.png靜態工廠設計模式

此種工廠設計模式屬於靜態工廠設計模式,也就是說如果現在要追加一個子類,則意味著工廠類一定要做出修改,因為如果不追加判斷是無法獲取指定接口對象的。
範例:為IMessage追加一個子類

public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        // IMessage msg = Factory.getInstance("netmessage");
        // msg.send();//【網絡消息發送】www.mldn.cn
        IMessage msg = Factory.getInstance("cloudmessage");
        msg.send();//【雲消息發送】www.mldnjava.cn
    }
}
interface IMessage{
    void send();  //消息發送
}
class NetMessage implements IMessage{
    @Override
    public void send() {
        System.out.println("【網絡消息發送】www.mldn.cn");
    }
}
class CloudMessage implements IMessage{
    @Override
    public void send() {
        System.out.println("【雲消息發送】www.mldnjava.cn");
    }
}
class Factory{
    private Factory(){}
    public static IMessage getInstance(String className){
        if("netmessage".equalsIgnoreCase(className)){
            return new NetMessage();
        }else if("cloudmessage".equalsIgnoreCase(className)){
            return new CloudMessage();
        }
        return null;
    }
}

工廠設計模式最有效的解決的是子類與客戶端的耦合問題,但是解決的核心思想是在於提供了一個工廠類作為過渡端,但是隨著項目的進行,IMessage接口有可能會擁有更多的子類,而且隨著時間的推移,子類產生的可能會越來越多,那麼此時就意味著,工廠類永遠都要進行修改,並且永無停止之日。

那麼這時候最好的解決方案就是不使用關鍵字new來完成,因為關鍵字在new在使用時,需要有一個明確的類存在。而newInstance()方法只需要有一個明確表示類名稱的字符串即可。

public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        IMessage msg = Factory.getInstance("cn.mldn.demo.NetMessage");
        msg.send();  //【網絡消息發送】www.mldn.cn
    }
}
interface IMessage{
    void send();  //消息發送
}
class NetMessage implements IMessage{
    public void send() {
        System.out.println("【網絡消息發送】www.mldn.cn");
    }
}
class CloudMessage implements IMessage{
    @Override
    public void send() {
        System.out.println("【雲消息發送】www.mldnjava.cn");
    }
}
class Factory{
    private Factory(){}
    public static IMessage getInstance(String className){
        IMessage instance = null;
        try {
            instance = (IMessage) Class.forName(className).getDeclaredConstructor().newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }
}

這時可以發現,利用反射機制實現的工廠設計模式,最大的優勢在於:對於接口子類的擴充將不再影響到工廠類的定義。

image.png反射工廠設計模式

但現在依然需要進一步思考,因為在實際的項目開發過程中,有可能會存在有大量的接口,並且這些接口都可能需要通過工廠類實例化,所以此時的工廠設計模式不應該只為IMessage接口服務,應該為所有接口服務。

public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        IMessage msg = Factory.getInstance("cn.mldn.demo.NetMessage",IMessage.class);
        msg.send();  //【網絡消息發送】www.mldn.cn
        IService service=Factory.getInstance("cn.mldn.demo.HouseService",IService.class);
        service.service();  //【服務】為您的住宿提供服務。
    }
}
class Factory{
    private Factory(){}
    /**
     * 獲取接口實例化對象
     * @param className 接口的子類
     * @param clazz 描述的是一個接口的類型
     * @return 如果子類存在則返回指定接口的實例化對象
     */
    @SuppressWarnings("unchecked")
    public static <T> T getInstance(String className,Class<T> clazz){
        T instance=null;
        try {
            instance=(T) Class.forName(className).getDeclaredConstructor().newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }
}
interface IService{
    void service();
}
class HouseService implements IService{
    @Override
    public void service() {
        System.out.println("【服務】為您的住宿提供服務。");
    }
}
interface IMessage{
    void send();//消息發送
}
class NetMessage implements IMessage{
    public void send() {
        System.out.println("【網絡消息發送】www.mldn.cn");
    }
}
class CloudMessage implements IMessage{
    @Override
    public void send() {
        System.out.println("【雲消息發送】www.mldnjava.cn");
    }
}

image.png

此時的工廠模式將不再受限於指定的接口,可以為所有的接口提供實例化服務,達到可重用性。

想學習更多的Java的課程嗎?從小白到大神,從入門到精通,更多精彩不容錯過!免費為您提供更多的學習資源。
本內容視頻來源於阿里雲大學

更多Java面向對象編程文章查看此處

Leave a Reply

Your email address will not be published. Required fields are marked *