走向面向對象的六大原則--迪米特原則

面向對象編程的六大原則


更好的可拓展性--迪米特原則
迪米特原則的英文全稱是Law of Demeter,縮寫是LOD,也稱為最少知識原則。
定義是:一個對象應該對其他對象有最少的了解。
直白的說,就是讓對象只與最直接的朋友進行聯系。那么什么是最直接朋友呢?每個對象都必然會與其他類有耦合關系,兩個對象之間互相耦合就為朋友關系,這種關系類型有很多,比如組合,聚合,依賴。
下面,我們就通過舉例來說明迪米特原則

相信在外務工的朋友,都有租房的經歷,一般情況下大家都會通過中介找房。我們通過租房進行舉例,我們設定條件為:我只要求房子的租金和面積,中介負責將合適的房子介紹給我。以下是代碼實例。

// 房子
public class House {
    public float area;
    public float price;

    public House(float area, float price) {
        this.area = area;
        this.price = price;
    }

    @Override
    public String toString() {
        return "House{" +
                "area=" + area +
                ", price=" + price +
                '}';
    }
}
// 中介
public class Agency {
    List<House> mHouses = new ArrayList<>();

    public Agency() {
        for (int i = 0; i < 5; i++) {
            mHouses.add(new House(100 + i, (100 + i) * 200));
        }
    }

    public List<House> getHouses() {
        return mHouses;
    }
}
//租戶
public class Tenant {
    public float houseArea;
    public float housePrice;
    public static final float diffPrice = 200.001f;
    public static final float diffArea = 0.00001f;

    public void rentHouse(Agency agency) {
        List<House> mHouses = agency.getHouses();
        for (House house : mHouses) {
            if (isRightHouse(house)) {
                System.out.println("找到合適的房子了!\n" + house.toString());
                break;
            }

        }
    }

    private boolean isRightHouse(House house) {
        return Math.abs(house.price - housePrice) < diffPrice
                && Math.abs(house.area - houseArea) < diffArea;
    }
}

從上面的代碼我們可以看到,我們的租戶類(Tenant)不僅依賴了中介類(Agency),還要頻繁地與我們的房子類(House)打交道。我們的需求是:我只要求房子的租金和面積,中介負責將合適的房子介紹給我。但是現在是我們拿到了一大堆房子數據然后自己進行分析和計算,這樣一來,中介的功能就被弱化了,并且導致我們的租戶類(Tenant)和房子類(House)的耦合過高,因為作為租戶而言,我們必須知道房子(House)的細節。而此時租戶類(Tenant)又和中介類(Agency)保持聯系。這個時候我們就有必要進行一定的代碼調整,去區分清楚,究竟誰是誰的直接朋友,讓我們的代碼清晰起來。
我們通過需求進行分析,可以得出以下幾點:

  • 租戶只負責租房,提出房子的大小要求和租金要求,其他的要交給中介來做。
  • 租戶不參與房子的分析比對。
  • 中介負責與客戶進行交流,并且為客戶進行房子的比對和篩選。

如此一來,我們可以根據需求對代碼進行如下調整:

public class Agency {
    List<House> mHouses = new ArrayList<>();

    public Agency() {
        for (int i = 0; i < 5; i++) {
            mHouses.add(new House(100 + i, (100 + i) * 200));
        }
    }

    public House rentHouse(float area, float price) {
        for (House house : mHouses) {
            if (isRightHouse(area, price, house)) {
                System.out.println("找到合適的房子了!\n" + house.toString());
                return house;
            }
        }
        return null;
    }

    private boolean isRightHouse(float area, float price, House house) {
        return Math.abs(house.price - price) < Tenant.diffPrice
                && Math.abs(house.area - area) < Tenant.diffArea;
    }
}

public class Tenant {
    public float houseArea;
    public float housePrice;
    public static final float diffPrice = 200.001f;
    public static final float diffArea = 0.00001f;

    public void rentHouse(Agency agency) {
        System.out.println("找到合適的房子了:" + agency.rentHouse(houseArea, housePrice));
    }
}

此處我們經過一些簡單的調整,將對房子是否符合要求的判斷放到了中介里,這其實本就應該是中介的職責,根據用戶設定的條件去尋找房子,找到了就告訴用戶就可以了。而用戶也不需要知道有多少房源,每個房子是什么樣,他只需要詢問中介,中介告知結果即可。
從上述代碼我們可以看到,我們通過一次簡單的代碼修改后,代碼的耦合性已經降低了很多,同時,他們都達成了與最直接的朋友聯系的條件,將各個角色從復雜的關系中抽離出來,使程序的耦合更低,穩定性更好。
這里我們再次回憶一下我們ImageLoader中的代碼,就拿SD卡緩存來說,ImageCache就是用戶的直接朋友,而SD卡緩存內部卻是使用了DiskCache實現,這個DiskCahce就不是用戶的直接朋友了,因此,其實用戶完全不需要知道有這樣的緩存存在,用戶只需要和ImageCache打交道就好了,我們之前的代碼我再次優化過,使用了JakeWhartonDiskLruCache,最后代碼如下:

public void put(String url, Bitmap bitmap) {
    DiskLruCache.Editor editor = null;
    //如果沒有在內存緩存和磁盤緩存中找到對對應的緩存,從網絡上請求數據
    //寫入緩存
    editor = mDiskLruCache.edit(url);
    try {
        if (editor != null) {
            OutputStream out = editor.newOutputStream(0);
            if (writeBitmapToDisk(value, out)) {
                //寫入SD卡
                editor.commit();
            } else {
                editor.abort();
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    CloseUtils.colse(out);
}

用戶在使用SD卡緩存的時候,根本不知道DiskLruCache的實現,這就很好地對用戶隱藏了具體的代碼實現。當你能夠自己去寫DiskLruCache的時候,你就可以隨意替換掉此處我們引用的JakeWharton大神的DiskLruCache了。


總結#

一不小心,六個章節的《走向面向對象的六大原則》就到此結束了,在這里感謝何紅輝、關愛民先生所著的《Android設計模式》一書,給我了很多啟發和靈感,并且示例上提供了很多借鑒。
時間總是很快,快到你都注意不到自己的胡渣子又冒出來了,在我們開發的過程中,最難的不是開發出用戶所需要的功能,而是在后續的升級和維護過程中,讓系統能夠擁抱變化,不因為版本的迭代更新而破壞模塊的完整性和代碼的條理性,保證代碼的低耦合,高可拓展性,高內聚,在經理了N個版本的迭代以后,軟件系統依舊能夠保持穩健,靈活,清晰的架構。
當然啦,這只是一個理想的情況,代碼迭代而引發的坑,我們爬的還少嗎?為了少爬坑,為了讓自己的代碼更漂亮,系統更穩定,我們必須朝著這個方向去努力,遵循面向對象的六大原則,就是我們走出的,第一步
明天的將會寫關于單例模式的一些理解和示例,感謝大家的一直支持,我們共同進步!
謝謝。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容