1. 程式人生 > 實用技巧 >設計模式系列(六)七大設計原則-----迪米特法則與合成複用原則

設計模式系列(六)七大設計原則-----迪米特法則與合成複用原則

迪米特法則

  • 一個物件應該對其他物件保持最少的瞭解
  • 類與類的關係越密切,耦合度越大
  • 迪米特法則又稱為 最少知道原則,即一個類 對自己依賴的類知道的越少越好。也就是說,對於被依賴的類不管多麼複雜,都儘量將邏輯封裝在類的內部。對外除了提供的 public 方法,不對外洩露任何資訊
  • 迪米特法則還有個更簡單的定義:只與 直接的朋友通訊
  • 直接的朋友:每個物件都會與其他物件有 耦合關係,只要兩個物件之間有耦合關係,我們就說這兩個物件之間是朋友關係。耦合的方式很多,依賴,關聯,組合,聚合等。其中,我們稱出現 成員變數,方法引數,方法返回值 中的類為直接朋友,而出現在 區域性變數中的類不是直接的朋友。也就是說,陌生的類最好不要以區域性變數的形式出現類的內部。

例項

  1. 有一個學校,下屬有各個學院和總部,現要求打印出學校總部員工ID 和學院員工的id
  2. 程式碼實現
public class Demeter1 {
	public static void main(String[] args) {
		//建立了一個SchoolManager 物件
		SchoolManager schoolManager = new SchoolManager();
		//輸出學院的員工id 和學校總部的員工資訊
		schoolManager.printAllEmployee(new CollegeManager());
	}
}

//學校總部員工類
class Employee {
	private String id;
	
	public void setId(String id) {
		this.id = id;
	}
	public String getId() {
		return id;
	}
}

//學院的員工類
class CollegeEmployee {
	private String id;
	public void setId(String id) {
		this.id = id;
	}
	public String getId() {
		return id;
	}
}

//管理學院員工的管理類
class CollegeManager {
	//返回學院的所有員工
	public List<CollegeEmployee> getAllEmployee() {
		List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
		for (int i = 0; i < 10; i++) { //這裡我們增加了10 個員工到list
			CollegeEmployee emp = new CollegeEmployee();
			emp.setId("學院員工id= " + i);
			list.add(emp);
		}
		return list;
	}
} 

//學校管理類
//分析SchoolManager 類的直接朋友類有哪些Employee、CollegeManager
//CollegeEmployee 不是直接朋友而是一個陌生類,這樣違背了迪米特法則
class SchoolManager {
//返回學校總部的員工
	public List<Employee> getAllEmployee() {
		List<Employee> list = new ArrayList<Employee>();
		for (int i = 0; i < 5; i++) { //這裡我們增加了5 個員工到list
			Employee emp = new Employee();
			emp.setId("學校總部員工id= " + i);
			list.add(emp);
	 	}
		return list;
	}
	//該方法完成輸出學校總部和學院員工資訊(id)
	void printAllEmployee(CollegeManager sub) {
	//分析問題
	//1. 這裡的CollegeEmployee 不是SchoolManager 的直接朋友
	//2. CollegeEmployee 是以區域性變數方式出現在SchoolManager
	//3. 違反了迪米特法則
	//獲取到學院員工
	List<CollegeEmployee> list1 = sub.getAllEmployee();
	System.out.println("------------學院員工------------");
	for (CollegeEmployee e : list1) {
		System.out.println(e.getId());
	}
	
	//獲取到學校總部員工
	List<Employee> list2 = this.getAllEmployee();
	System.out.println("------------學校總部員工------------");
	for (Employee e : list2) {
		System.out.println(e.getId());
	}
	}
}

改進

  1. 說明
  • 前面設計的問題在於 SchoolManager 中,CollegeEmployee 類並不是SchoolManager 類的直接朋友(分析)
  • 按照迪米特法則,應該避免類中出現這樣非直接朋友關係的耦合
  1. 程式碼
//客戶端
public class Demeter1 {
	public static void main(String[] args) {
		System.out.println("~~~使用迪米特法則的改進~~~");
		//建立了一個SchoolManager 物件
		SchoolManager schoolManager = new SchoolManager();
		//輸出學院的員工id 和學校總部的員工資訊
		schoolManager.printAllEmployee(new CollegeManager());
	}
}
//學校總部員工類
class Employee {
	private String id;
	public void setId(String id) {
		this.id = id;
	}
	public String getId() {
		return id;
	}
}

//學院的員工類
class CollegeEmployee {
	private String id;
	public void setId(String id) {
		this.id = id;
	}
	public String getId() {
		return id;
	}
}
//管理學院員工的管理類
class CollegeManager {
	//返回學院的所有員工
	public List<CollegeEmployee> getAllEmployee() {
		List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
		for (int i = 0; i < 10; i++) { //這裡我們增加了10 個員工到list
			CollegeEmployee emp = new CollegeEmployee();
			emp.setId("學院員工id= " + i);
			list.add(emp);
		}
	 	return list;
	 }
	//輸出學院員工的資訊
	public void printEmployee() {
		//獲取到學院員工
		List<CollegeEmployee> list1 = getAllEmployee();
		System.out.println("------------學院員工------------");
		for (CollegeEmployee e : list1) {
			System.out.println(e.getId());
		}
	}
}

//學校管理類
//分析SchoolManager 類的直接朋友類有哪些Employee、CollegeManager
//CollegeEmployee 不是直接朋友而是一個陌生類,這樣違背了迪米特法則
class SchoolManager {
	//返回學校總部的員工
	public List<Employee> getAllEmployee() {
		List<Employee> list = new ArrayList<Employee>();
		for (int i = 0; i < 5; i++) { //這裡我們增加了5 個員工到list
			Employee emp = new Employee();
			emp.setId("學校總部員工id= " + i);
			list.add(emp);
		}
		return list;
 	}
	//該方法完成輸出學校總部和學院員工資訊(id)
	void printAllEmployee(CollegeManager sub) {
		//分析問題
		//1. 將輸出學院的員工方法,封裝到CollegeManager
		sub.printEmployee();
		//獲取到學校總部員工
		List<Employee> list2 = this.getAllEmployee();
		System.out.println("------------學校總部員工------------");
		for (Employee e : list2) {
			System.out.println(e.getId());
		}
	}
}
  1. 注意事項
  • 迪米特法則的核心是降低類之間的耦合
  • 但是注意:由於每個類都減少了不必要的依賴,因此迪米特法則只是要求降低類間(物件間)耦合關係, 並不是
    要求完全沒有依賴關係

合成複用原則

合成複用原則設計的核心思想:

  • 找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的程式碼混在一起。
  • 針對介面程式設計,而不是針對實現程式設計。
  • 為了互動物件之間的 鬆耦合設計而努力