Java 通過工廠模式和接口泛型實現完全解耦

首先我們假設:

  • 有一個農民(farmer)
  • 有一本菜譜(cookbook),爲了方便理解菜譜只有炸雞這一個菜

假設這是程序的兩部分,分別可以被單獨複用.並且農民被複用時有時需要菜譜上的函數做飯,有時忙不過來,就不按照菜譜做飯了,直接泡方便麪.

如果不夠詳細的話可以這麼理解:

農民是單身,所以爲了回家不捱餓,他在瀏覽器裏收藏了一個菜譜.也就是說,農民主要被用來幹活,但不管是務農還是扛磚,爲了不餓着每天都要帶着手機看菜譜.但農民根據僱主的不同,不會每天都按照菜譜做飯,因爲有時太忙了,就隨便泡個方便麪喫,然後繼續幹活.

而炸雞的菜譜不止農民收藏了,鎮子裏的100個飯店也收藏了,飯店跟農民一毛錢關係都沒有,飯店需要可以直接照着菜譜做飯.

所以:

  • 這個菜譜誰都可以用
  • 這個農民可以被任何老闆僱傭
  • 有的老闆僱傭農民時不許帶手機,只能泡方便麪,所以菜譜與農民不總在一起.

此時文件結構爲:

  • 文件夾 farmer
    • 類Cook
    • 接口CookingMethod
    • 接口CookingMaterial
    • 類CookingFactory
  • cookbook
    • 類Chicken
    • 接口ChickenInterf
    • 類FryMethod
    • 接口FryInterf

farmer下有一個Cook類,這個類中有個方法要製作午餐.但此時不能直接調用Chicken與FryMethod.因爲有可能不讓帶菜譜,只能喫泡麪.

所以,不能在Cook類中出現Chicken與FryMethod.而要農民定義出對食材與方法的要求,也就是接口.無論中午喫什麼食材(方便麪還是雞肉),都要滿足農夫的要求CookingMaterial.無論是炸(雞)還是泡(面),都要滿足CookingMethod.至於選擇炸雞還是泡麪,則由CookingFactory選擇,選擇完後,對應給農民的CookingMaterial和CookingMethod(就是方法的重載罷了).也就是說,如果farmer文件夾下出現Chicken與FryMethod,那麼只可能是在CookingFactory類中.注意不可避免的是,每次這個農民被拿去用,這個類都要按需手動修改.

public class Cook {

    public void cook() {
        CookingMaterial material = new CookingFactory().getCookingMaterial();
        CookingMethod method = new CookingFactory().getCookingMethod();
    }

}
public class CookingFactory {

    public CookingMaterial getCookingMaterial() {
        return new Chicken();
    }

    public CookingMethod getCookingMethod() {
        return new FryMethod();
    }

}
public interface CookingMaterial {
    void printMaterialName();
}
public interface CookingMethod {
    void heatFood(CookingMaterial material);
}

這樣就實現了farmer包每次被拿去用,只要改CookingFactory這一個文件就好.至於爲什麼不直接改Cook類,因爲Cook類中可能有10000處地方使用了Chicken,不可能挨着改的,CookingFactory則只將Chicken與CookingMaterial對接.然後在Cook類中所有需要使用Chicken的地方全寫CookingMaterial就好了.

至此農民可被獨立使用的問題解決了.


但菜譜也要被獨立使用,如果FryMethod繼承了農民的CookingMethod那麼飯店就不能用了.所以菜譜也定義出它自己的接口FryMethodInterf.然後FryMethod繼承FryMethodInterf.可是別人拿去怎麼用呢?好的,每個使用菜譜的人,不管是農民還是白領還是廚師,都要提供自己的要求給菜譜,然後菜譜的FryMethodInterf繼承所有這些要求(接口是可以多繼承的),這些要求不能被滿足的話就在FryMethod裏完善.

這樣實現了菜譜的相對獨立,缺點是這本菜譜非常厚,因爲它詳細的介紹了大廚應該怎麼做炸雞,白領應該怎麼做炸雞,農民應該怎麼做炸雞,有點像維基百科了,但也沒關係,因爲每個人用的時候只會用到關於自己的部分.也就是說菜譜單獨使用時,只需要在FryMethodInterf裏添加一些繼承,然後把沒有的方法在FryMethod中補上.

public interface ChickenInterf extends CookingMaterial {
    //這裏留空即可,有用的這個接口都繼承了,沒用的寫出來也沒用-_-
}
public class Chicken implements ChickenInterf {

    @Override
    public void printMaterialName() {
        System.out.println("chicken");
    }

}
public interface FryMethodInterf extends CookingMethod {
}
public class FryMethod implements FryMethodInterf {
    @Override
    public void heatFood(CookingMaterial material) {
        //balabalala
    }
}

好像很完美,等等!!!FryMethod裏爲毛出現了農民的CookingMaterial作爲參數????這個heat難道不是所有人做炸雞都要用到的Chicken嗎???

直接將CookingMaterial換成Chicken就不是覆寫了,顯然不行!!!那就泛型吧.

直接改成泛型也是不行的,要改動三個類四處地方:

  • CookingMethod改爲
public interface CookingMethod<C extends CookingMaterial> {
    void heatFood(C material);
}
  • FryMethodInterf改爲
public interface FryMethodInterf extends CookingMethod<Chicken> {
}
  • FryMethod改爲
public class FryMethod implements FryMethodInterf {
    @Override
    public void heatFood(Chicken material) {
        //balabalala
    }
}

至此,cookbook下只有接口的繼承中出現了farmer文件夾下的內容,別的程序用時刪掉即可,同一程序不同模塊用時只要多繼承上這個模塊的接口就好;farmer下只有CookingFactory中有cookbook的內容,如果需要可以很方便替換成paofangbianmian文件夾下的內容.基本上實現了沒有第三方接口存在下的完全解耦.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章