91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java 如何更好地管理你的對象

發布時間:2020-09-16 10:07:55 來源:億速云 閱讀:168 作者:小新 欄目:編程語言

這篇文章主要介紹了Java 如何更好地管理你的對象,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。

有一天晚上我腦海中突然冒出來一個問題:“怎樣管理我們代碼中的對象”。

小弈是剛工作時的我,他說:通過 new 來創建一個對象然后直接使用就好了啊。

public class HelloWorld {
public void hello() {
System.out.println("hello world!");
}
}
HelloWorld helloWorld = new HelloWorld();
helloWorld.hello();

你們看,我有一個 HelloWorld 類,我用 new 就能直接創建一個對象,然后就能使用這個對象中所有的方法了,多簡單啊。

二弈是工作兩年的我,他一臉鄙視的對小弈說,你別整天 HelloWorld 好不好,還有啊,除了 new 你就不會其他的了,能不能有點追求啊?

小弈對二弈說那你說除了 new 還有什么辦法啊?

二弈說可以通過 Class 的 newInstance 或者 Constructor 的 newInstance 來創建對象實例啊。

不過你得記住,Class 的 newInstance 只能對那些擁有可見的(Accessible)無參構造函數的類,才能進行對象的實例化,而 Constructor 就沒有這些限制。

大弈是工作三年的我,他說,雖然你們的方法都可以用來創建對象,但都還是手動創建的,太原始了,生產力太低。

工欲善其事,必先利其器,我們也得找個高效的生產力工具。IOC 容器你們了解吧?

以前我們在一個對象中如果要調用另外一個對象的方法時,都是通過 new 或者反射來手動創建該對象,但是每次都這樣做太累了,并且類之間的耦合也很高。

通過 IOC 容器,我們可以把所有的對象交給容器來管理,在使用之前只需要定義一下對象,然后再使用到該對象時,IOC 容器就會幫我們把該對象初始化好,這樣是不是更方便呢?

大弈說完,舉了一個例子:

@Bean
public class RegisterService {
public void register() {
// do register
}
}
@Bean
public class LoginService {
public void login() {
// do login
}
}
@Bean
public class HelloWorld {
@Autowired
private RegisterService registerService;
@Autowired
private LoginService loginService;
public void hello() {
// 注冊
registerService.register();
// ...
// 登錄
loginService.login();
}
}

IOC 容器通過一種叫 Bean 的注解,在系統啟動時掃描所有通過 Bean 標注的類,對這些類進行實例化,然后將所有的對象都保存在容器中。再掃描所有通過 Autowired 標注的屬性或者方法,從容器中找到與之匹配(通過名稱或者類型等)的對象將具體的對象賦值給這些屬性。這樣我們就可以直接將這些對象拿來使用了,作為一個伸手黨是不是很幸福啊。

老弈是工作五年的我,他聽了大弈的話后,提出了一個問題,對于新的項目可以使用這種 IOC 的容器,可是對于那些遺留的老項目來說,要使用 IOC 來改造是不太符合實情的。

我舉個例子,在一個遺留的老項目中,有一個核心的接口 Handler:

public interface Handler<REQ, RES> {
    RES handle(REQ request);
}

Handler 接口有很多的實現類,我們需要對不同的請求來調用不同的 Handler 實現類進行處理,如果用 IOC 容器來管理這些實現類,顯然不太合適,因為我們處理之前是不知道該用哪個 Handler 實現類的。

大弈想了想,如果 Handler 接口只有幾個固定的實現類,并且在使用時只會使用一個來進行處理,那么倒是可以在啟動前通過配置的方式來確定具體使用哪種 Handler ,比如可以通過 @Conditional 根據某些條件來確定加載具體的對象,但是這種要在使用時才能確定 Handler 對象的類型確實比較棘手。

老弈看大家都不說話了,就繼續說了下去。

為了要在調用方法時使用不同的 Handler 來處理不同的而請求,需要確定兩種類,一種是請求類,一種是處理類,并且要讓請求類和處理類一一對應起來。

假設我們的請求類是一個 Packet 類,每一個具體的請求類都繼承自這個基類。

那么想要確定每一個具體的 Packet 是什么類型的,可以有很多種方法,可以為每個 Packet 取一個唯一的名字,例如:

public abstract class Packet {
    public abstract String name();
}

也可以為每一個 Packet 指定一個標志,例如:

public abstract class Packet {
    public abstract int symbol();
}

但是不管哪種方式,每一個 Packet 的實現類都需要實現抽象類中的方法,來“標志”自己是哪種 Packet。

我們以第二種方式舉例,假設我們有兩個具體的 Packet:

public class RegisterPacket extends Packet {
// 注冊所需要的其他參數
int symbol() {
return 1;
}
}
public class LoginPacket extends Packet {
// 登錄所需要的其他參數
int symbol() {
return 2;
}
}

這樣當我們接收到 request 對象時,通過調用 request.symbol() 就知道這個 request 是哪種類型的 Packet 了,這時只要找到具體的 Handler 實現類來處理就可以了。

那請求類已經可以確定了,怎樣確定 Handler 處理類呢?我們是否也可以在 Handler 接口中定義一個 symbol 方法呢,像這樣:

public interface Handler<REQ, RES> {
    int symbol();
    RES handle(REQ request);
}

這樣的話,只要在所有的實現類中實現 symbol 方法來標注該 Handler 是用來處理何種 request 的即可。

public RegisterHandler implements Handler<RegisterPacket, RES> {
    int symbol(){
    return 1;
    }
    RES handle(RegisterPacket request){
    // 具體的處理方法
    }
}
public LoginHandler implements Handler<LoginPacket, RES> {
    int symbol(){
    return 2;
    }
    RES handle(LoginPacket request){
    // 具體的處理方法
    }
}

最后把所有的 Handler 實現類都實例化后保存在一個 HandlerProvider 中,要使用時再到 HandlerProvider 中來獲取即可:

public interface HandlerProvider {
    Handler getHandler(int symbol);
}

那怎樣獲取到所有的 Handler 的實現類呢,有兩種方法。

一種是通過 ServiceLoader.load(Handler.class) 的方式來獲取,不過這種通過 spi 的方式需要在項目的 resources/META-INF/services/ 目錄下創建一個 xxx.Handler 的文件,并在文件中將所有 Handler 的實現類的完全類限定符列出來。

另一種比較簡單的方式是通過掃描的方式,獲取到所有 Handler 的實現類。

到現在為止,我們的實現還算可以,但是有一個問題,那就是在 Handler 接口中我們增加了一個方法,這樣做就對原來的代碼進行了侵入。

為了讓原來的代碼保持不變,我們可以定義一個注解來標注在所有的 Handler 實現類上,比如這樣:

@Symbol(1)
public RegisterHandler implements Handler<RegisterPacket, RES> {
    RES handle(RegisterPacket request){
    // 具體的處理方法
    }
}
@Symbol(2)
public LoginHandler implements Handler<LoginPacket, RES> {
    RES handle(LoginPacket request){
    // 具體的處理方法
    }
}

這樣就將 Handler 的實現和標注進行了解耦了,也可以通過掃描 @Symbol 注解來獲取到所有的 Handler 實現類,不過這樣做的缺點就是假如我忘記對某個 Handler 實現類添加 @Symbol 注解,到時候就獲取不到該 Handler 了。

大家聽完老弈的話之后,都陷入了沉思,我靠,還可以這么玩,真有趣。

這時候現在的我,也就是逅弈,說了一句,如果我有一個接口,他只有幾個固定的實現類,我不想搞那一套那么重的實現方式,但是我也需要動態的獲取實現類來對請求進行處理,那我該怎么辦呢?

比如我有一個序列化的接口,如下所示:

public interface Serializer {
    byte[] serialize(Packet packet);
}

然后只有五種具體的序列化的實現類,如下所示:

public class JdkSerializer implements Serializer {
@Override
    public byte[] serialize(Packet packet) {
    // 具體的序列化操作
    }
}
public class FastJsonSerializer implements Serializer {
@Override
    public byte[] serialize(Packet packet) {
    // 具體的序列化操作
    }
}
public class HessianSerializer implements Serializer {
@Override
    public byte[] serialize(Packet packet) {
    // 具體的序列化操作
    }
}
public class KryoSerializer implements Serializer {
@Override
    public byte[] serialize(Packet packet) {
    // 具體的序列化操作
    }
}
public class ProtoStuffSerializer implements Serializer {
@Override
    public byte[] serialize(Packet packet) {
    // 具體的序列化操作
    }
}

那么我們該怎么確定使用哪種序列化方式對參數 packet 進行序列化呢?

使用老弈剛剛說的那一套也確實能夠實現,不過太麻煩了,又得對 Packet 定義 symbol,又得對 Hander 實現類進行標注,還得掃描所有的實現類。

我只有五個實現類,不需要搞那么麻煩的。

其實很簡單,只需要定義一個枚舉類,表示序列化的算法,然后對 Packet 增加一個 algorithm 方法用來表示,使用何種序列化算法,如下所示:

public enum SerializeAlgorithm {
    JDK((byte) 1),
    FAST_JSON((byte) 2),
    HESSIAN((byte) 3),
    KRYO((byte) 4),
    PROTO_STUFF((byte) 5);
    private byte type;
    SerializeAlgorithm(byte type) {
        this.type = type;
    }
}
public abstract class Packet implements Serializable {
public abstract byte algorithm();
}

然后定義一個 SerializerChooser 根據不同的算法選擇不同的 Serializer 實現類即可:

public interface SerializerChooser {
    Serializer choose(byte algorithm);
}

因為根據算法是可以知道對應的序列化接口的,所以就沒有必要去掃描了,直接把幾種序列化的實現類枚舉出來即可,對象的實例可以使用單例模式,如下所示:

public class DefaultSerializerChooser implements SerializerChooser {
    private DefaultSerializerChooser() {
    }
    public static SerializerChooser getInstance() {
        return Singleton.get(DefaultSerializerChooser.class);
    }
    @Override
    public Serializer choose(byte algorithm) {
        SerializeAlgorithm serializeAlgorithm = SerializeAlgorithm.getEnum(algorithm);
        switch (serializeAlgorithm) {
            case JDK: {
                return Singleton.get(JdkSerializer.class);
            }
            case FAST_JSON: {
                return Singleton.get(FastJsonSerializer.class);
            }
            case HESSIAN: {
                return Singleton.get(HessianSerializer.class);
            }
            case KRYO: {
                return Singleton.get(KryoSerializer.class);
            }
            case PROTO_STUFF: {
                return Singleton.get(ProtoStuffSerializer.class);
            }
            default: {
                return null;
            }
        }
    }
}

我說完后,大家又一次陷入了沉思,我知道大家都在思考,他們會在每一次思考中獲得進步和成長,正如我在思考后得到成長一樣。

感謝你能夠認真閱讀完這篇文章,希望小編分享Java 如何更好地管理你的對象內容對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,遇到問題就找億速云,詳細的解決方法等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

博白县| 苏尼特左旗| 宁化县| 天祝| 锦屏县| 龙里县| 本溪| 乐陵市| 定襄县| 木里| 南城县| 镇安县| 民权县| 沙雅县| 兴仁县| 隆化县| 宜都市| 炉霍县| 依安县| 寿光市| 阳高县| 星子县| 湘西| 巴林左旗| 长春市| 渑池县| 天长市| 勃利县| 高平市| 延长县| 九龙坡区| 栾川县| 张家港市| 信丰县| 鲜城| 南充市| 诏安县| 寻甸| 抚州市| 东光县| 广南县|