合成模式把部分和整體關係用樹結構表示,是屬於對象的結構模式。合成模式要對組合的對象進行管理,所以在一定位置給予對象的相關管理方法,如:add(),remove()等.合成模式中對象的管理有兩種方案。
1.安全方式:此方式只允許樹枝構件有對象的管理方法。
2.透明方式:此方式只允許樹枝和樹葉都有對象的管理方法,但樹葉對象中的管理方法無實際意義。
一.UML示意圖
二.組成部分
抽象構件:抽象組合對象的公共行爲接口
樹葉構件:樹葉對象,沒有下級子對象
樹枝構件:樹枝對象,樹枝對象可以包含一個或多個其他樹枝或樹葉對象
三.代碼例子:我以一個超市購物爲例
(一)、安全方式
1.抽象物品(抽象構件)
- package com.eekq.structure.composite.security;
- /*
- * 抽象構件,物品
- * */
- public interface IRes {
- /**購物買單,示意性的商業方法*/
- public void pay();
- }
2.單一物品(樹葉構件)
- package com.eekq.structure.composite.security;
- public class SingleResImpl implements IRes {
- /**物品名稱*/
- private String name;
- /**價錢*/
- private float money;
- public SingleResImpl(String name, float money) {
- this.name = name;
- this.money = money;
- }
- public void pay() {
- System.out.println("購買了一件物品["+getName()+"],價錢是[" + getMoney()+"]元");
- }
- public float getMoney() {
- // TODO 自動生成方法存根
- returnthis.money;
- }
- public String getName() {
- // TODO 自動生成方法存根
- return this.name;
- }
- /**重寫equals*/
- public boolean equals(Object obj){
- SingleResImpl res = (SingleResImpl)obj;
- return res.getName().equals(getName()) && res.getMoney()==getMoney();
- }
- }
3.多個物品(樹枝構件)
- package com.eekq.structure.composite.security;
- import java.util.Iterator;
- import java.util.Vector;
- /*
- * 對多個物品的管理
- * */
- public class MultiResImpl implements IRes {
- /**購物車*/
- private Vector car = new Vector();
- private static float totle = 0.0f;
- public void pay() {
- if(!car.isEmpty()){
- System.out.println("名稱 價格\n");
- shopping();
- System.out.println("\n總價:" + totle + "元");
- }else{
- System.out.println("您好,你沒有購買任何物品,不用買單!");
- }
- }
- public void shopping() {
- if (car != null || !car.isEmpty()) {
- Iterator it = car.iterator();
- SingleResImpl res = null;
- Object temp = null;// 臨時對象
- while (it.hasNext()) {
- temp = it.next();
- if (temp instanceof MultiResImpl) {
- ((MultiResImpl) temp).shopping();
- } else {
- res = (SingleResImpl) temp;
- synchronized (this) {
- totle += res.getMoney();
- }
- System.out.println(res.getName() + " " + res.getMoney()
- + "元");
- }
- }
- }
- }
- /**加入新的物品*/
- public void addRes(IRes res) {
- car.add(res);
- }
- /**放回物品*/
- public void removeRes(IRes res) {
- car.remove(res);
- }
- }
4.收銀臺買單
- package com.eekq.structure.composite.security;
- public class Main {
- /**
- *@paramargs
- */
- public static void main(String[] args) {
- /**買支雪糕*/
- IRes singleRes = new SingleResImpl("雪糕", 1.5f);
- /**買單*/
- singleRes.pay();
- /**快過年了,我推了個購物車,多買點東西*/
- IRes allRes = new MultiResImpl();
- /**在一樓買的食物*/
- IRes one = new MultiResImpl();
- ((MultiResImpl) allRes).addRes(one);//把一樓的東西裝在購物車裏
- /**因爲是安全方式的組合模式,因此不夠透明,只能明確的向下轉型,然後再加入購物車了*/
- ((MultiResImpl) one).addRes(new SingleResImpl("旺旺", 28.5f));
- ((MultiResImpl) one).addRes(new SingleResImpl("糖果", 38.0f));
- ((MultiResImpl) one).addRes(new SingleResImpl("可樂", 8.5f));
- /**二樓去買的衣服和襪子*/
- IRes two = new MultiResImpl();
- ((MultiResImpl) allRes).addRes(two);// 把二樓的東西裝也裝在購物車裏
- ((MultiResImpl) two).addRes(new SingleResImpl("衣服", 130.5f));
- ((MultiResImpl) two).addRes(new SingleResImpl("襪子", 10f));
- /**二樓再買了個手錶,我放在bao裏*/
- IRes bao = new MultiResImpl();
- ((MultiResImpl) two).addRes(bao);//把購物小包裝在二樓購物車裏
- ((MultiResImpl) bao).addRes(new SingleResImpl("手錶", 100f));
- /**回到一樓,又買了蘋果和梨*/
- ((MultiResImpl) one).addRes(new SingleResImpl("蘋果", 10.0f));
- ((MultiResImpl) one).addRes(new SingleResImpl("梨", 3.0f));
- /**在買單之前我把可樂退了,因爲家裏還有的嘛*/
- ((MultiResImpl) one).removeRes(new SingleResImpl("可樂", 8.5f));
- /**在收銀臺一次性對購物車所有物品買單*/
- allRes.pay();
- }
- }
5.運行結果
購買了一件物品[雪糕],價錢是[1.5]元
名稱 價格
旺旺 28.5元
糖果 38.0元
蘋果 10.0元
梨 3.0元
衣服 130.5元
襪子 10.0元
手錶 100.0元
總價:320.0元
(二)、透明方式
透明方式與安全方式的不同點在於抽象構件,透明方式使用的是統一接口。
1. 抽象構件
- package com.eekq.structure.composite.clarity;
- /*
- * 抽象構件,物品
- * */
- public interface IRes {
- /**購物買單,示意性的商業方法*/
- public void pay();
- /**加入新的物品*/
- public void addRes(IRes res);
- /**放回物品*/
- public void removeRes(IRes res);
- }
2. 單一物品(樹葉構件)
- package com.eekq.structure.composite.security;
- public class SingleResImpl implements IRes {
- /**物品名稱*/
- private String name;
- /**價錢*/
- private float money;
- public SingleResImpl(String name, float money) {
- this.name = name;
- this.money = money;
- }
- public void pay() {
- System.out.println("購買了一件物品["+getName()+"],價錢是[" + getMoney()+"]元");
- }
- public float getMoney() {
- // TODO 自動生成方法存根
- return this.money;
- }
- public String getName() {
- // TODO 自動生成方法存根
- return this.name;
- }
- /**重寫equals*/
- public boolean equals(Object obj){
- SingleResImpl res = (SingleResImpl)obj;
- return res.getName().equals(getName()) && res.getMoney()==getMoney();
- }
- }
3.多個物品(樹枝構件)
同安全模式代碼一樣!
4.收銀臺買單
- package com.eekq.structure.composite.clarity;
- public class Main {
- /**
- *@paramargs
- */
- public static void main(String[] args) {
- /**買支雪糕*/
- IRes singleRes = new SingleResImpl("雪糕", 1.5f);
- /**買單*/
- singleRes.pay();
- /**快過年了,我推了個購物車,多買點東西*/
- IRes allRes = new MultiResImpl();
- /**在一樓買的食物*/
- IRes one = new MultiResImpl();
- allRes.addRes(one);// 把一樓的東西裝在購物車裏
- /**因爲是透明方式的組合模式,因此直接調用就是了*/
- one.addRes(new SingleResImpl("旺旺", 28.5f));
- one.addRes(new SingleResImpl("糖果", 38.0f));
- one.addRes(new SingleResImpl("可樂", 8.5f));
- /**二樓去買的衣服和襪子*/
- IRes two = new MultiResImpl();
- allRes.addRes(two);// 把二樓的東西裝也裝在購物車裏
- two.addRes(new SingleResImpl("衣服", 130.5f));
- two.addRes(new SingleResImpl("襪子", 10f));
- /**二樓再買了個手錶,我放在bao裏*/
- IRes bao = new MultiResImpl();
- two.addRes(bao);// 把購物小包裝在二樓購物車裏
- bao.addRes(new SingleResImpl("手錶", 100f));
- /**回到一樓,又買了蘋果和梨*/
- one.addRes(new SingleResImpl("蘋果", 10.0f));
- one.addRes(new SingleResImpl("梨", 3.0f));
- /**在買單之前我把可樂退了,因爲家裏還有的嘛*/
- one.removeRes(new SingleResImpl("可樂", 8.5f));
- /**在收銀臺一次性對購物車所有物品買單*/
- allRes.pay();
- }
- }
5.運行結果
同安全模式一樣的結果!
四.總結
合成模式是對象的結構模式,以上演示合成模式。在以後的項目中,如果遇到對象組合的情況,即也符合樹結構的。可以考慮下此模式。此模式中講述了安全方式和透明方式。
安全方式:抽象構件上只提供樹葉和樹枝公共的方法,沒提供樹枝獨有的管理等方法(add(),remove())。這樣的好處是安全,用戶不會在樹葉上使用add()等管理方法,缺點是不夠透明,用戶必須知識當前對象爲樹葉還是樹枝(向下轉型)。
透明方式:抽象構件上提供了滿足樹枝的所有方法(包括add(),remove()),這樣做的好處是,用戶可以任意執行對象的add()和remove()管理對象。缺點是如果用戶在樹葉上執行管理方式(add(),remove())時,在編譯期不會有錯,但在執行期會報錯,這樣不容易被發覺錯誤出在哪.