伊莉討論區

標題: 請問高手們關於版本抽換問題[問題][已解決] [打印本頁]

作者: ahway9988    時間: 2019-9-30 07:59 AM     標題: 請問高手們關於版本抽換問題[問題][已解決]

本帖最後由 ahway9988 於 2019-10-4 06:28 AM 編輯

最近在練習關於MVC架構的設計,當中有遇到了版本抽換的問題:範例程式如下
我定義專案名稱為:MyVersion
抽象父類:AV
版本接口:IV
子類:V1、V2

問題:
版本抽換應該是一件利於管理程式的設計方式,使得管理者不用改動大量的程式,
甚至於改錯了造成更嚴重的問題。
所以盡可能地不要再去打開原來的程式碼修改,而是使用繼承的方法,但以下的方法似乎還不夠,所以我想連MyVersion都不用改,用一種修改文件檔的方法,如
PHP伺服器中,有時需要修改.ini 檔一樣。
修改文字檔也能做到版本更換的效果嗎?

--------------------------------------------------------

MyVersion的程式:
package myversion;

public class MyVersion {
    public static void main(String[] args) {
        System.out.println("======V1======");
        IV v1 = new V1();
        v1.setMsg("Hello World Java");
        v1.sayHello();

        System.out.println("======V2======");
        IV v2 = new V2();
        v2.setMsg("Hello World PHP");
        v2.sayHello();
    }
}

輸出結果:
======V1======
[V1] 'Hello World Java'  time:Mon Sep 30 07:42:36 CST 2019
======V2======
[V2] 'Hello World PHP'  時間:Mon Sep 30 07:42:36 CST 2019

--------------------------------------------------------

AV的程式:
package myversion;

public abstract class AV<T> {
    protected T msg;
    protected abstract T getMsg();
}

--------------------------------------------------------

IV的程式:
package myversion;

public interface IV <T>{
    void setMsg(T msg);
    void sayHello();
}

--------------------------------------------------------

V1的程式:
package myversion;
import java.util.Date;

public class V1 extends AV implements IV<String> {
    @Override
    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    protected String getMsg() {
        String myMsg = String.format("'%s'  time:%s", this.msg, new Date());
        return myMsg;
    }

    @Override
    public void sayHello() {
        String myMsg = "[V1] " + this.getMsg();
        System.out.println(myMsg);
    }
}

--------------------------------------------------------

V2的程式:
package myversion;
import java.util.Date;

public class V2 extends AV implements IV<String> {
    @Override
    public void setMsg(String msg) {
        this.msg=msg;
    }

    @Override
    public String getMsg() {
        String myMsg = String.format("'%s'  時間:%s", this.msg, new Date());
        return myMsg;
    }

    @Override
    public void sayHello() {
        String myMsg="[V2] "+this.getMsg();
        System.out.println(myMsg);
    }
}

以上範例可能舉例地不夠好,但其實只要看MyVersion裡的敍述就可以了。














作者: codewice    時間: 2019-10-1 09:25 PM

本帖最後由 codewice 於 2019-10-1 09:26 PM 編輯

Java 有個東西叫 ServiceLoader,透過 META-INF 目錄底下的檔案設定,來決定要讀進哪一個 class 的實作,這是我直覺想到的東西。

看你的問題,我覺得有幾個名詞可能會產生誤解。譬如說「版本抽換」,很容易被想成 version replacement,我猜你想表達的是 implementation replacement。雖然說不同的 version 也隱含著不同的 implementation,但是 version 通常用在產品版本的語意,如果是在工程或架構上面的替換,我建議使用 implementation (實作)。

在實務上,能不能透過設定檔來抽換其實算比較小的事情,最困難的是能不能有良好的介面(interface)設計,讓你可以無痛抽換。如果整個專案有良好的程式碼品質,抽換實作的時候不會發生問題,那麼是不是要用設定檔,我覺得像是 90 分跟 100 分的差距。但是許多案子裡面,根本連介面都設計不好,一堆 down cast。

實作抽換的應用,不只在 MVC/MVP/MVVM 這些 Pattern 裡面,它其實是常見的一個原則:「要針對介面去寫程式,不要針對實作寫程式」。這點可能要多寫點程式會比較有體會

另外,「繼承」絕對不是被鼓勵為重用程式碼的方法。不是說繼承本身有問題,而是沒有深思熟慮的繼承,反倒很容易寫出不容易維護的程式。所以 Kotlin 語言預設就把 class 設定為 final class (不准繼承),如果真的想要利用繼承,必須要手動宣告為 open class,讓你大聲說出:「對,我想清楚了,老子現在就是要用繼承!」

也許是我多想。從你的範例裡面,如果我是團隊的 reviewer,會問幾個問題

1. 為什麼要用 generic?
2. AV 沒有任何實作,為什麼要宣告成 abstract class?

也許你只是為了簡化例子才會用現在的寫法,不然根據現在的 AV, IV 的設計還有「extends AV implements IV<String>」看起來很像只是為了過 compiling 而湊出來的寫法。(做最小更動的話,我覺得 setMsg 擺在 AV 裡面比較合理)

作者: ahway9988    時間: 2019-10-2 08:17 AM

codewice 發表於 2019-10-1 09:25 PM
Java 有個東西叫 ServiceLoader,透過 META-INF 目錄底下的檔案設定,來決定要讀進哪一個 class 的實作,這 ...

還好一樓大還懂得我所說的,那範例是我從netbeans 產生的程式碼form ejb
好像叫ORM 工程 ,一個叫DAO 工廠模式的結構,去簡化修改的。
可能名詞也引用不當,課程上我只大概了解一下這些名詞。
但課程中講到XML 這似乎不太好懂。
而且在一般APP也能用XML 嗎? 所以我想是不是有別的方法可以取代。
像php 那種 修改.ini 檔的方法 來配置組態。
我查找了一下ServiceLoader的用法,似乎就是他了。引述自網上文章:通過ServiceLoader來實現一些類似的功能。而不用依賴像Spring這樣的第三方框架。
這樣看來 ServiceLoader 是關鍵字, 謝謝一樓大大提供的答案^^


作者: kwj    時間: 2019-10-4 12:09 AM

談到抽換直覺就會想到 Inversion of Control。

另外以現在的發展來說,不太會特別強調要抽換時「不要改程式碼」,因為基於 config as code 的背景之下,改設定檔跟改程式碼其實沒什麼不同了。要點還是在於 OCP(Open-Closed Principle)的原則,也就是要擴充現有功能時盡可能不要改到已經寫好的程式碼,而這點也是樓上大大有提到的,關鍵在於能不能設計出好的介面。




歡迎光臨 伊莉討論區 (http://a04.eyny.com/) Powered by Discuz!