将程序的组成转换成有上下阶级的结构(或称:树状结构),方便使用者不论从哪个节点、叶子使用,都可以有相似的执行。
假入要撰写一个程序,本身是参考现实世界中有上下阶级的组织时,而且每个组织的上中下游部门,都可以「提供相同的服务」时,就可以采用 Composite 模式,或者称作树状结构(资料结构的树状图)。
现实中常见的范例有:
Composite 模式强调每个节点都可以提供相同的服务,因此作法会是:
节点、叶子亲代:MilitaryUnit
public abstract class MilitaryUnit {
protected String name;
protected int unitCounts;
protected int weaponCounts;
protected MilitaryUnit(String name, int unitCounts, int weaponCounts) {
this.name = name;
this.unitCounts = unitCounts;
this.weaponCounts = weaponCounts;
}
public abstract void add(MilitaryUnit unit);
public abstract void remove(MilitaryUnit unit);
public abstract void display(int depth);
public abstract int reportUnitCounts();
public abstract int reportWeaponCounts();
}
节点子代:ConcreteMilitaryUnit
public class ConcreteMilitaryUnit extends MilitaryUnit {
private ArrayList<MilitaryUnit> militaryUnits = new ArrayList<MilitaryUnit>();
public ConcreteMilitaryUnit(String name) {
super(name, 0, 0);
}
@Override
public void add(MilitaryUnit unit) {
militaryUnits.add(unit);
}
@Override
public void remove(MilitaryUnit unit) {
militaryUnits.remove(unit);
}
@Override
public void display(int depth) {
char[] title = new char[depth];
Arrays.fill(title, '-');
System.out.println(new String(title) + name);
for (MilitaryUnit unit : militaryUnits) {
unit.display(depth + 2);
}
}
@Override
public int reportUnitCounts() {
for (MilitaryUnit militaryUnit : militaryUnits) {
unitCounts += militaryUnit.reportUnitCounts();
}
return unitCounts;
}
@Override
public int reportWeaponCounts() {
for (MilitaryUnit militaryUnit : militaryUnits) {
weaponCounts += militaryUnit.reportWeaponCounts();
}
return weaponCounts;
}
}
叶子子代:NormalSoldier
、LazySoldier
、DrunkSoldier
、DeserterSoldier
public class NormalSoldier extends MilitaryUnit {
public NormalSoldier(String name) {
super(name, 1, 1);
}
@Override
public void add(MilitaryUnit unit) {
}
@Override
public void remove(MilitaryUnit unit) {
}
@Override
public void display(int depth) {
char[] title = new char[depth];
Arrays.fill(title, '-');
System.out.println(new String(title) + name);
}
@Override
public int reportUnitCounts() {
return unitCounts;
}
@Override
public int reportWeaponCounts() {
return weaponCounts;
}
}
public class LazySoldier extends MilitaryUnit {
public LazySoldier(String name) {
super(name, 1, 0);
}
@Override
public void add(MilitaryUnit unit) {
}
@Override
public void remove(MilitaryUnit unit) {
}
@Override
public void display(int depth) {
char[] title = new char[depth];
Arrays.fill(title, '-');
System.out.println(new String(title) + name);
}
@Override
public int reportUnitCounts() {
return unitCounts;
}
@Override
public int reportWeaponCounts() {
return weaponCounts;
}
}
public class DrunkSoldier extends MilitaryUnit {
public DrunkSoldier(String name) {
super(name, 1, 3);
}
@Override
public void add(MilitaryUnit unit) {
}
@Override
public void remove(MilitaryUnit unit) {
}
@Override
public void display(int depth) {
char[] title = new char[depth];
Arrays.fill(title, '-');
System.out.println(new String(title) + name);
}
@Override
public int reportUnitCounts() {
return unitCounts;
}
@Override
public int reportWeaponCounts() {
return weaponCounts;
}
}
public class DeserterSoldier extends MilitaryUnit {
public DeserterSoldier(String name) {
super(name, 0, 1);
}
@Override
public void add(MilitaryUnit unit) {
}
@Override
public void remove(MilitaryUnit unit) {
}
@Override
public void display(int depth) {
char[] title = new char[depth];
Arrays.fill(title, '-');
System.out.println(new String(title) + name);
}
@Override
public int reportUnitCounts() {
return unitCounts;
}
@Override
public int reportWeaponCounts() {
return weaponCounts;
}
}
测试:ArmyCompositeSample
public class ArmyCompositeSample {
public static void main(String[] args) {
MilitaryUnit army = new ConcreteMilitaryUnit("陆军");
army.add(new NormalSoldier("司令"));
army.add(new NormalSoldier("陆军通讯兵"));
MilitaryUnit division = new ConcreteMilitaryUnit("第一师");
division.add(new NormalSoldier("师长"));
division.add(new NormalSoldier("第一师通讯兵"));
army.add(division);
MilitaryUnit brigade = new ConcreteMilitaryUnit("第一旅");
brigade.add(new NormalSoldier("旅长"));
brigade.add(new NormalSoldier("第一旅通讯兵"));
division.add(brigade);
MilitaryUnit regiment = new ConcreteMilitaryUnit("第一团");
regiment.add(new NormalSoldier("团长"));
regiment.add(new NormalSoldier("第一团通讯兵"));
brigade.add(regiment);
MilitaryUnit battalion = new ConcreteMilitaryUnit("第一营");
battalion.add(new NormalSoldier("营长"));
battalion.add(new NormalSoldier("第一营通讯兵"));
regiment.add(battalion);
MilitaryUnit company = new ConcreteMilitaryUnit("第一连");
company.add(new NormalSoldier("连长"));
company.add(new NormalSoldier("第一连通讯兵"));
battalion.add(company);
MilitaryUnit platoon = new ConcreteMilitaryUnit("第一排");
platoon.add(new NormalSoldier("排长"));
platoon.add(new NormalSoldier("第一排通讯兵"));
company.add(platoon);
MilitaryUnit squad1 = new ConcreteMilitaryUnit("第一班");
squad1.add(new NormalSoldier("班长"));
squad1.add(new NormalSoldier("第一班通讯兵"));
platoon.add(squad1);
MilitaryUnit fireTeam11 = new ConcreteMilitaryUnit("第一伍");
fireTeam11.add(new NormalSoldier("伍长"));
fireTeam11.add(new NormalSoldier("第一伍通讯兵"));
fireTeam11.add(new NormalSoldier("Roger"));
fireTeam11.add(new NormalSoldier("Jason"));
squad1.add(fireTeam11);
MilitaryUnit fireTeam12 = new ConcreteMilitaryUnit("第二伍");
fireTeam12.add(new NormalSoldier("伍长"));
fireTeam12.add(new LazySoldier("第二伍通讯兵"));
fireTeam12.add(new DrunkSoldier("Rick"));
fireTeam12.add(new DeserterSoldier("Jay"));
squad1.add(fireTeam12);
MilitaryUnit squad2 = new ConcreteMilitaryUnit("第二班");
squad2.add(new NormalSoldier("班长"));
squad2.add(new NormalSoldier("第二班通讯兵"));
platoon.add(squad2);
MilitaryUnit fireTeam21 = new ConcreteMilitaryUnit("第三伍");
fireTeam21.add(new NormalSoldier("伍长"));
fireTeam21.add(new DrunkSoldier("第三伍通讯兵"));
fireTeam21.add(new NormalSoldier("Allen"));
fireTeam21.add(new NormalSoldier("Bill"));
squad2.add(fireTeam21);
MilitaryUnit fireTeam22 = new ConcreteMilitaryUnit("第四伍");
fireTeam22.add(new NormalSoldier("伍长"));
fireTeam22.add(new LazySoldier("第四伍通讯兵"));
fireTeam22.add(new DrunkSoldier("Charlie"));
fireTeam22.add(new DeserterSoldier("Dave"));
squad2.add(fireTeam22);
System.out.println("结构图:");
army.display(1);
System.out.println("陆军人员回报:" + army.reportUnitCounts());
System.out.println("陆军武器数量回报:" + army.reportWeaponCounts());
}
}
节点、叶子亲代:MilitaryUnit
/** @abstract */
class MilitaryUnit {
constructor(name, unitCounts, weaponCounts) {
this.name = name;
this.unitCounts = unitCounts | 0;
this.weaponCounts = weaponCounts | 0;
}
/** @abstract */
add(unit) { return; }
/** @abstract */
remove(unit) { return; }
/** @abstract */
display(depth) { return; }
/** @abstract */
reportUnitCounts() { return; }
/** @abstract */
reportWeaponCounts() { return; }
}
节点子代:ConcreteMilitaryUnit
class ConcreteMilitaryUnit extends MilitaryUnit {
constructor(name) {
super(name);
/** @type MilitaryUnit[] */
this.militaryUnits = [];
}
/** @override */
add(unit) {
this.militaryUnits.push(unit);
}
/** @override */
remove(unit) {
this.militaryUnits = this.militaryUnits.filter((curUnit) => curUnit !== unit);
}
/** @override */
display(depth) {
console.log('-'.repeat(depth) + this.name);
for (const unit of this.militaryUnits) {
unit.display(depth + 2);
}
}
/** @override */
reportUnitCounts() {
for (const militaryUnit of this.militaryUnits) {
this.unitCounts += militaryUnit.reportUnitCounts();
}
return this.unitCounts;
}
/** @override */
reportWeaponCounts() {
for (const militaryUnit of this.militaryUnits) {
this.weaponCounts += militaryUnit.reportWeaponCounts();
}
return this.weaponCounts;
}
}
叶子子代:NormalSoldier
、LazySoldier
、DrunkSoldier
、DeserterSoldier
class NormalSoldier extends MilitaryUnit {
constructor(name) {
super(name, 1, 1);
}
/** @override */
add(unit) {
return;
}
/** @override */
remove(unit) {
return;
}
/** @override */
display(depth) {
console.log('-'.repeat(depth) + this.name);
}
/** @override */
reportUnitCounts() {
return this.unitCounts;
}
/** @override */
reportWeaponCounts() {
return this.weaponCounts;
}
}
class LazySoldier extends MilitaryUnit {
constructor(name) {
super(name, 1, 0);
}
/** @override */
add(unit) {
return;
}
/** @override */
remove(unit) {
return;
}
/** @override */
display(depth) {
console.log('-'.repeat(depth) + this.name);
}
/** @override */
reportUnitCounts() {
return this.unitCounts;
}
/** @override */
reportWeaponCounts() {
return this.weaponCounts;
}
}
class DrunkSoldier extends MilitaryUnit {
constructor(name) {
super(name, 1, 3);
}
/** @override */
add(unit) {
return;
}
/** @override */
remove(unit) {
return;
}
/** @override */
display(depth) {
console.log('-'.repeat(depth) + this.name);
}
/** @override */
reportUnitCounts() {
return this.unitCounts;
}
/** @override */
reportWeaponCounts() {
return this.weaponCounts;
}
}
class DeserterSoldier extends MilitaryUnit {
constructor(name) {
super(name, 0, 1);
}
/** @override */
add(unit) {
return;
}
/** @override */
remove(unit) {
return;
}
/** @override */
display(depth) {
console.log('-'.repeat(depth) + this.name);
}
/** @override */
reportUnitCounts() {
return this.unitCounts;
}
/** @override */
reportWeaponCounts() {
return this.weaponCounts;
}
}
测试:armyCompositeSample
const armyCompositeSample = () => {
const army = new ConcreteMilitaryUnit("陆军");
army.add(new NormalSoldier("司令"));
army.add(new NormalSoldier("陆军通讯兵"));
const division = new ConcreteMilitaryUnit("第一师");
division.add(new NormalSoldier("师长"));
division.add(new NormalSoldier("第一师通讯兵"));
army.add(division);
const brigade = new ConcreteMilitaryUnit("第一旅");
brigade.add(new NormalSoldier("旅长"));
brigade.add(new NormalSoldier("第一旅通讯兵"));
division.add(brigade);
const regiment = new ConcreteMilitaryUnit("第一团");
regiment.add(new NormalSoldier("团长"));
regiment.add(new NormalSoldier("第一团通讯兵"));
brigade.add(regiment);
const battalion = new ConcreteMilitaryUnit("第一营");
battalion.add(new NormalSoldier("营长"));
battalion.add(new NormalSoldier("第一营通讯兵"));
regiment.add(battalion);
const company = new ConcreteMilitaryUnit("第一连");
company.add(new NormalSoldier("连长"));
company.add(new NormalSoldier("第一连通讯兵"));
battalion.add(company);
const platoon = new ConcreteMilitaryUnit("第一排");
platoon.add(new NormalSoldier("排长"));
platoon.add(new NormalSoldier("第一排通讯兵"));
company.add(platoon);
const squad1 = new ConcreteMilitaryUnit("第一班");
squad1.add(new NormalSoldier("班长"));
squad1.add(new NormalSoldier("第一班通讯兵"));
platoon.add(squad1);
const fireTeam11 = new ConcreteMilitaryUnit("第一伍");
fireTeam11.add(new NormalSoldier("伍长"));
fireTeam11.add(new NormalSoldier("第一伍通讯兵"));
fireTeam11.add(new NormalSoldier("Roger"));
fireTeam11.add(new NormalSoldier("Jason"));
squad1.add(fireTeam11);
const fireTeam12 = new ConcreteMilitaryUnit("第二伍");
fireTeam12.add(new NormalSoldier("伍长"));
fireTeam12.add(new LazySoldier("第二伍通讯兵"));
fireTeam12.add(new DrunkSoldier("Rick"));
fireTeam12.add(new DeserterSoldier("Jay"));
squad1.add(fireTeam12);
const squad2 = new ConcreteMilitaryUnit("第二班");
squad2.add(new NormalSoldier("班长"));
squad2.add(new NormalSoldier("第二班通讯兵"));
platoon.add(squad2);
const fireTeam21 = new ConcreteMilitaryUnit("第三伍");
fireTeam21.add(new NormalSoldier("伍长"));
fireTeam21.add(new DrunkSoldier("第三伍通讯兵"));
fireTeam21.add(new NormalSoldier("Allen"));
fireTeam21.add(new NormalSoldier("Bill"));
squad2.add(fireTeam21);
const fireTeam22 = new ConcreteMilitaryUnit("第四伍");
fireTeam22.add(new NormalSoldier("伍长"));
fireTeam22.add(new LazySoldier("第四伍通讯兵"));
fireTeam22.add(new DrunkSoldier("Charlie"));
fireTeam22.add(new DeserterSoldier("Dave"));
squad2.add(fireTeam22);
console.log("结构图:");
army.display(1);
console.log("陆军人员回报:" + army.reportUnitCounts());
console.log("陆军武器数量回报:" + army.reportWeaponCounts());
}
armyCompositeSample();
Composite 是个好理解但是不容易实作的模式,原因有两点:
符合需求的话,建构起来不麻烦,使用者只要参考规格就可以安心呼叫。
参考以上几点,理解 Composite 是特殊要求下的解。
明天将介绍 Structural patterns 的第四个模式:Decorator 模式。
>>: 【Day 15】反向传播(Backpropagation)
大家好,我是毛毛。ヾ(´∀ ˋ)ノ 废话不多说开始今天的解题Day~ 9. Palindrome N...
物件导向的设计中,关於建构物件的方式我们成为建构器(constructor),这关系到物件使用的方式...
Background 对於变数的Type,能够依据他们的特性分为两种,分别为不可变的Static t...
Hei,我是Charlie! 在Day17当中,我们完成了後端的结帐功能,在今天我们将完成前端的结帐...
修正Bug日 [ ] 修正首页的排版问题 [ ] 修正书本细节页面的排版问题 [ ] 修正新增照片到...