一、引入組合模式
設計一個大學>學院>專業的結構代碼,可以做到輸出大學、學院、專業的信息。
- 一個大學裏面有多個學院
- 一個學院裏面有多個專業
思路
我們很容易就想到這種組合的方式,去設計我們的代碼。完全沒有問題,可以很好的去實現我們的功能。
但是後面如果變動的時候就麻煩了。 假如我們要讓大學直接去使用專業呢?
二、組合模式
組合模式(Composite Pattern) 將對象組合成樹形結構以表示“部分-整體”的層次結構。組合模式使得用戶可以使用一致的方法操作單個對象和組合對象。
組合模式有三個角色:
組合部件(Component):它可以是抽象類、接口、類。它裏面定義了基本的屬性和方法。
合成部件(Composite):還有自己的子節點,比如這裏的大學、學院。
葉子(Leaf):在組合中表示子節點對象,比如這裏的專業。
代碼演示
Component
import lombok.Data;
@Data
public abstract class Component {
protected String name;
protected void add(Component component){
throw new UnsupportedOperationException();
}
protected void remove(Component component){
throw new UnsupportedOperationException();
}
abstract void print();
}
注:
1、比如我們上面的大學裏面有學院,那麼它就需要添加一個學院(add())和刪除一個學院(remove())。但是我們的專業(也就是葉子節點),它不需要這個添加和刪除方法,所以我們進行一個默認實現,裏面拋出這個異常表示不支持此方法。
2、這裏爲什麼不用接口呢?(JDK8之後允許接口有默認實現),因爲接口裏面不允許定義非常量的變量。
University
import java.util.ArrayList;
import java.util.List;
public class University extends Component {
private List<Component> lists = new ArrayList<>();
public University(String name){
super();
setName(name);
}
@Override
public void add(Component component) {
lists.add(component);
}
@Override
public void remove(Component component) {
lists.remove(component);
}
@Override
public void print() {
System.out.println("----------"+getName()+"----------");
for (Component c : lists){
c.print();
}
}
}
College
import java.util.ArrayList;
import java.util.List;
public class College extends Component {
private List<Component> lists = new ArrayList<>();
public College(String name){
super();
setName(name);
}
@Override
public void add(Component component) {
lists.add(component);
}
@Override
public void remove(Component component) {
lists.remove(component);
}
@Override
public void print() {
System.out.println("----------"+getName()+"----------");
for (Component c : lists){
c.print();
}
}
}
Major
public class Major extends Component {
public Major(String name){
super();
setName(name);
}
@Override
void print() {
System.out.println(getName());
}
}
測試
public class Main {
public static void main(String[] args) {
// 創建學校
University university = new University("沙雕大學");
// 創建學院
College college_1 = new College("計算機與科學學院");
College college_2 = new College("人文藝術學院");
// 大學與學院關聯
university.add(college_1);
university.add(college_2);
// 創建專業
Major major_1 = new Major("軟件工程");
Major major_2 = new Major("網絡工程");
Major major_3 = new Major("音樂與舞蹈");
Major major_4 = new Major("表演與藝術");
// 學院與專業關聯
college_1.add(major_1);
college_1.add(major_2);
college_2.add(major_3);
college_2.add(major_4);
// 測試
// 打印大學
university.print();
// ----------沙雕大學----------
// ----------計算機與科學學院----------
// 軟件工程
// 網絡工程
// ----------人文藝術學院----------
// 音樂與舞蹈
// 表演與藝術
// 打印學院
college_1.print();
// ----------計算機與科學學院----------
// 軟件工程
// 網絡工程
// 打印專業
major_1.print();
// 軟件工程
}
}
總結
- 客戶端只需要面對對象即可,不需要考慮整體部分和葉子節點的問題。
- 具有較強的擴展性。當我們需要更改組合對象時,我們只需要調整內部的層次關係即可。
- 需要遍歷組織機構,或者處理的對象具有樹形結構時,非常適合使用組合模式。
- 如果節點和葉子有很多差異的話,比如很多屬性、或方法不一樣,就不適合使用組合模式了。