題外話
本來是周更的頻率, 因為真實的"小光"真實地逃離了北京, 回了武漢, 回了老家, 處理了一些私人事務. 也就有快一個月時間沒有更新了, 抱歉.
年終總結(jié)也都沒有時間寫, 抽空寫這么一篇, 提前祝大家新年快樂, 過年回家路上平安順利.
前情提要
上集講到, 小光統(tǒng)一了各個分店的制作熱干面的流程, 并且引入模板方法在不改變熱干面的制作流程基礎(chǔ)上可以定制其中某些步驟. 通過這些措施, 小光熱干面的品牌性也是更加深入人心, 生意紅紅火火.
此時的小光, 有了更多的時間去思考公司的前程, 他認為, 一個良好的有序的組織架構(gòu)是公司發(fā)展的必要點. 而此時, 小光也有覺得是時候梳理下公司的組織架構(gòu)了.
所有示例源碼已經(jīng)上傳到Github, 戳這里
組織架構(gòu)
小光參考了當前很多公司的一些架構(gòu)方式, 根據(jù)分店, 職責簡單梳理了下目前小光熱干面的架構(gòu):
整個就是一個樹形結(jié)構(gòu).
- 小光熱干面總部下面管理著各個分店, 也有其自己的部門.
- 各個分店也有著自己的部門.
設(shè)計一套系統(tǒng)來表達這個組織架構(gòu)
梳理完組織關(guān)系后, 小光覺得有必要設(shè)計一套系統(tǒng)來管理這個關(guān)系圖, 以便后續(xù)能方便的查看和管理這個架構(gòu), 并能很清晰地講解給新員工.
簡單的開始
一開始, 小光并沒有想太多, 按照不同的層級, 分別創(chuàng)建了總公司, 分店, 部門三個類:
// 部門
public class Department {
private String name;
public Department(String name) {
this.name = name;
}
@Override
public String toString() {
return "部門:" + name;
}
}
// 分店
public class BranchOffice {
private String name;
public BranchOffice(String name) {
this.name = name;
}
private List<Department> departments = new ArrayList<>();
public void add(Department sub) {
departments.add(sub);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder("分公司:" + name);
for (Department dept : departments) {
builder.append(" - " + dept.toString());
}
return builder.toString();
}
}
// 總公司
public class HeadOffice {
private String name;
public HeadOffice(String name) {
this.name = name;
}
private List<Department> departments = new ArrayList<>();
public void add(Department sub) {
departments.add(sub);
}
private List<BranchOffice> branches = new ArrayList<>();
public void add(BranchOffice branchOffice) {
branches.add(branchOffice);
}
public void print() {
System.out.println("總公司:" + name);
for (BranchOffice branch : branches) {
System.out.println(" - " + branch);
}
for (Department dept : departments) {
System.out.println(" - " + dept);
}
}
}
利用這些層次的類來組成小光的組織架構(gòu):
public class XiaoGuang {
public static void main(String[] args) {
HeadOffice headOffice = new HeadOffice("小光熱干面");
Department financeDept = new Department("財務部");
Department strategyDept = new Department("策劃部");
BranchOffice ov = new BranchOffice("光谷分店");
ov.add(financeDept);
ov.add(strategyDept);
BranchOffice huashan = new BranchOffice("花山分店");
huashan.add(financeDept);
huashan.add(strategyDept);
headOffice.add(financeDept);
headOffice.add(strategyDept);
headOffice.add(ov);
headOffice.add(huashan);
headOffice.print();
}
}
結(jié)果如下, 達到要求:
總公司:小光熱干面
- 分公司:光谷分店 - 部門:財務部 - 部門:策劃部
- 分公司:花山分店 - 部門:財務部 - 部門:策劃部
- 部門:財務部
- 部門:策劃部
小光的思考
看著這新鮮出爐的架構(gòu)程序, 小光總覺得哪兒不對勁兒. 畢竟小光是歷經(jīng)了北上廣各種類型公司的人才啊, 回想起上班敲代碼的日子, 小光想起了哪兒不妥了. 公司總會發(fā)展, 發(fā)展過程中總會有一些戰(zhàn)略調(diào)整, 從而導致公司部門的各種變化.
目前小光設(shè)計的組織架構(gòu)是三層架構(gòu), 但是隨著公司的發(fā)展壯大, 很有可能層級會變得更多. 比如說, 總部的采購部壯大了, 可能會增加下一級的食材采購部和設(shè)備采購部. 甚至可能現(xiàn)在的層級還會隨著公司的戰(zhàn)略調(diào)整而升降. 例如, 如果分店開到別的城市了, 可能會在總部和分店之間插入一層"子公司"來分別管理各地的分店. 如下:
那么就出現(xiàn)了一個我們一直在強調(diào)的問題: 有些東西可能會一直有變化, 而我們從產(chǎn)品角度肯定會想要擁抱變化, 然而代碼層面上我們又不想修改代碼(修改原有代碼意味著還有對原有邏輯負責).
那應該怎么辦呢? 有沒有更好的方式來表達這種樹形的組織架構(gòu)關(guān)系呢? 以便能夠很容易地擴展層次呢?
小光又回想起了自己的碼農(nóng)時代, 回想當年這種問題的解決方案:
既然是因為變化, 擴展而引起的問題, 我們最重要是要先找出系統(tǒng)中可變和不可變的部分, 封裝不可變(使其修改關(guān)閉), 擁抱可變(使其擴展開放).
小光的解決之道
那么具體到這個組織系統(tǒng)架構(gòu)的問題, 又該怎么做呢?
小光可不想每增加一個層級都要重新為其增加一個類, 然后改變原有系統(tǒng). 特別是有些情況下, 曾加的類(子公司)中可能會包含分店和自己的部門. 隨著類別的增加, 每次增加一個層級將會越來越難.
小光想到著, 突然想到:
每個部門/分店/子公司乃至總公司不都是部門的集合嗎?
部門可能有下屬部門, 可能沒有
分店下有部門
子公司下有分店, 可能還有自己的部門
總公司下有子公司, 分店, 自己的部門
所以說, 所有實體(總公司/子公司/分店/部門)實際上都是由部門組成的. 這些實體也都可以看著是一個部門.
想到做到:
首先定義出基礎(chǔ)的部門:
public class Department {
private String name;
public Department(String name) {
this.name = name;
}
private List<Department> subDepartments = new ArrayList<>();
public void add(Department sub) {
subDepartments.add(sub);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder(name);
for (Department dept : subDepartments) {
builder.append("\n");
builder.append(" - " + dept.toString());
}
return builder.toString();
}
}
來看下, 利用Department這一個類別怎么搭建組織:
public class XiaoGuang {
public static void main(String[] args) {
Department financeDept = new Department("財務部");
Department strategyDept = new Department("策劃部");
Department ovBranchOffice = new Department("光谷分店");
ovBranchOffice.add(financeDept);
ovBranchOffice.add(strategyDept);
Department huashanBranchOffice = new Department("花山分店");
huashanBranchOffice.add(financeDept);
huashanBranchOffice.add(strategyDept);
Department wuhanChildOffice = new Department("武漢子公司");
wuhanChildOffice.add(ovBranchOffice);
wuhanChildOffice.add(huashanBranchOffice);
Department changshaChildOffice = new Department("長沙子公司");
Department xiaoguang = new Department("小光熱干面");
xiaoguang.add(wuhanChildOffice);
xiaoguang.add(changshaChildOffice);
xiaoguang.add(financeDept);
xiaoguang.add(strategyDept);
System.out.println(xiaoguang);
}
}
輸出如下
小光熱干面
- 武漢子公司
- 光谷分店
- 財務部
- 策劃部
- 花山分店
- 財務部
- 策劃部
- 長沙子公司
- 財務部
- 策劃部
輸出稍有調(diào)整, 以顯示直觀的層級. 大家可以自行修改下代碼, 來給department加入level屬性, 以便輸出更完美的結(jié)構(gòu).
到此, 我們算是解決了組織架構(gòu)的問題了, 以后不管是增加了什么層級, 我們都只需要使用Department來表示即可, 而無需增加一個類了.
故事之后
照例, 我們來縷縷小光設(shè)計的這套系統(tǒng)的"類關(guān)系":
結(jié)構(gòu)相當簡單, 實際上就是一個類, 其中關(guān)鍵的是: 這個類中有一個list屬性(subDepartments)包含的是一組該類. 有點遞歸的感覺.
這個就是我們今天想說的 --- 組合模式
組合模式
又叫部分整體模式,通過組合的方式, 創(chuàng)建一個包含了一組自己的對象組(List<Department>)的類(Department). 從而達成了用一個類來遞歸地表示一個整體.組合模式通常用來解決樹形結(jié)構(gòu)的表達問題, 例如本例中的組織結(jié)構(gòu).
所謂組合的方式, 就是創(chuàng)建一個包含了一組自己的對象組的類
注: 我們這里實現(xiàn)的相對簡單, 旨在說明模式的形式.
實際場景中, Department可能是一個抽象的, 例如有一個抽象方法來執(zhí)行該部門的職責, 有不同的具體部門實現(xiàn)來實現(xiàn)其職責. 從而有不同的"Department實現(xiàn)"來組合另一個大的Department節(jié)點.
擴展閱讀一
前面說到, 組合模式通常用來處理樹形結(jié)構(gòu)的表達問題. 而我們的用戶界面實現(xiàn)通常就是一個UI元素的節(jié)點樹. 例如HTML中的div中可能有button, 還會有其他div層級, 依次往下; Java SE中的界面實現(xiàn)AWT和Swing包也到處是組合模式的體現(xiàn); Android中的View體系, View和ViewGroup, Layout層級樹也都是組合模式的體現(xiàn).
在此我們以Android的View體系為例, 簡單描述下.
眾所周知, Android的界面實際上就是一顆大樹, Hierarchy Viewer中展示的就是一個樹形結(jié)構(gòu). 我們來看下Android是怎么利用組合模式實現(xiàn)的.
如下:
- ViewGroup就是相當于例子中的Department, 這里面比我們的例子復雜的是, ViewGroup是擴展自View的, View實際上我們可以理解為是葉子節(jié)點, 也就是最小的組成單元了, 不再有以下的層級了.
- ViewGroup中包含了一組View對象, 因為ViewGroup是View的子類, 故而我們也可以說ViewGroup中包含了一組ViewGroup和/或View. 進入形成了我們之前說的遞歸, 生成一個樹形結(jié)構(gòu).
關(guān)于View的體系, 在此不細述了.
搭建好彈性可擴展的組織架構(gòu)體系, 小光又開始將眼光轉(zhuǎn)移到市場, 轉(zhuǎn)移到業(yè)務了, 準備著新年大展拳腳~