今天為大家介紹組合模式 ( Composite Pattern ) 。
目的
對樹形結構的中間節點和葉子節點對客戶端保持一致的處理。
例子代碼
最近全國都在新型冠狀病毒引起的肺炎的影響之下。從年前隱隱約約聽說這個病毒, 到截止寫文章的這個時候, 根據@今日頭條的數據來看, 目前全國確診 2823 例, 死亡 81 例。
連我們這個 10086 線的城市都有確診案例。希望大家少串門,做好預防工作。
這次我也是領悟到了, 平安健康就是最好的, 希望大家都能夠平安健康。
大家目前應該是希望能夠進行消毒操作, 下面我們模擬給湖北省消毒的一段代碼:
我們先定義一個省的結構:
<code>@Datapublic class Province { private String name; private List<city> cities = new ArrayList<>(); public Province(String name) { this.name = name; } public void killVirus() { cities.forEach(City::killVirus); } public void addCity(City city) { cities.add(city); } public void removeCity(City city) { cities.remove(city); }}/<city>/<code>
省是由市組成的:
<code>@Datapublic class City { private String name; private List<mall> malls = new ArrayList<>(); private List<school> schools = new ArrayList<>(); public City(String name) { this.name = name; } public void killVirus() { malls.forEach(Mall::killVirus); schools.forEach(School::killVirus); } public void addMall(Mall mall) { malls.add(mall); } public void removeMall(Mall mall) { malls.remove(mall); } public void addSchool(School school) { schools.add(school); } public void removeSchool(School school) { schools.remove(school); }}/<school>/<mall>/<code>
市裡面有商場和學校是消毒的重點:
商場:
<code>@Datapublic class Mall { private String name; public Mall(String name) { this.name = name; } public void killVirus() { System.out.println("給" + name + "商場區域消毒"); }}/<code>
學校:
<code>@Datapublic class School { private String name; public School(String name) { this.name = name; } public void killVirus() { System.out.println("給" + name + "學校區域消毒"); }}/<code>
我們嘗試進行消毒:
<code>Province province = new Province("湖北省");City wuhan = new City("武漢市");wuhan.addMall(new Mall("華南海鮮市場"));wuhan.addSchool(new School("武漢一中"));province.addCity(wuhan);City huanggang = new City("黃岡市");huanggang.addMall(new Mall("家樂福"));huanggang.addSchool(new School("黃岡一中"));province.addCity(huanggang);province.killVirus();/<code>
問題分析
這個裡面有一個很嚴重的問題, 就是如果我們再加一個醫院也作為消毒的場所, city 類就需要改, 再加一個辦公樓也作為消毒場所, city 類還需要改, city 類累了。
組合模式
我們先定義一個節點間共有的接口:
<code>public interface Place { void add(Place place); void remove(Place place); void killVirus();}/<code>
定義通用的中間節點的實現:
<code>public abstract class AbstractCompositePlace implements Place { private List<place> list = new ArrayList<>(); @Override public void add(Place place) { list.add(place); } @Override public void remove(Place place) { list.remove(place); } @Override public void killVirus() { list.forEach(Place::killVirus); }}/<place>/<code>
定義通用的葉子節點的實現:
<code>public abstract class AbstractLeafPlace implements Place { @Override public void add(Place place) { } @Override public void remove(Place place) { }}/<code>
再來定義我們之前的幾個類:
<code>@Datapublic class Province extends AbstractCompositePlace { private String name; public Province(String name) { this.name = name; }}/<code>
<code>@Datapublic class City extends AbstractCompositePlace { private String name; public City(String name) { this.name = name; }}/<code>
<code>@Datapublic class Mall extends AbstractLeafPlace { private String name; public Mall(String name) { this.name = name; } @Override public void killVirus() { System.out.println("給" + name + "商場區域消毒"); }}/<code>
<code>@Datapublic class School extends AbstractLeafPlace { private String name; public School(String name) { this.name = name; } @Override public void killVirus() { System.out.println("給" + name + "學校區域消毒"); }}/<code>
然後我們的客戶端代碼如下:
<code>Place province = new Province("湖北省");Place wuhan = new City("武漢市");wuhan.add(new Mall("華南海鮮市場"));wuhan.add(new School("武漢一中"));province.add(wuhan);Place huanggang = new City("黃岡市");huanggang.add(new Mall("家樂福"));huanggang.add(new School("黃岡一中"));province.add(huanggang);province.killVirus();/<code>
輸出如下:
<code>給華南海鮮市場商場區域消毒給武漢一中學校區域消毒給家樂福商場區域消毒給黃岡一中學校區域消毒/<code>
類圖如下:
最近,老媽作為一個鄉村醫生, 每天都在挨家挨戶的量體溫, 排查外來人口, 去鎮上開會彙報兩個村子的情況, 還帶個簡單的口罩頂著感染的風險去給鄉親們打針輸液。在此,向每一位醫療工作者致敬!
閱讀更多 codog代碼狗 的文章