一,什麼是組合模式
Composite 模式 也叫組合模式,是構造型的設計模式之一,通過遞歸手段來構造樹形的對象結構,並可以通過一個對象來訪問整個對象樹
二,組合模式的結構
組合模式的角色和職責
Component : (樹形結構的節點抽象)
- 爲所有的對象定義統一的接口,(公共屬性,行爲等的定義)
- 提供管理子節點對象的接口方法
- (選擇)提供管理父節點對象的接口方法
Leaf : (樹形結構的葉節點)
Composite: (樹形結構的枝節點)
優點:
- 組合模式使得客戶端代碼可以一致地處理單個對象和組合對象,無須關心自己處理的是單個對象,還是組合對象,這簡化了客戶端代碼;
- 更容易在組合體內加入新的對象,客戶端不會因爲加入了新的對象而更改源代碼,滿足“開閉原則”;
缺點:
- 設計較複雜,客戶端需要花更多時間理清類之間的層次關係;
- 不容易限制容器中的構件;
- 不容易用繼承的方法來增加構件的新功能;
組合模式分爲透明式的組合模式和安全式的組合模式。
四:透明方式代碼實現:
透明方式:在該方式中,由於抽象構件聲明瞭所有子類中的全部方法,所以客戶端無須區別樹葉對象和樹枝對象,對客戶端來說是透明的。但其缺點是:樹葉構件本來沒有 Add()、Remove() 及 GetChild() 方法,卻要實現它們(空實現或拋異常),這樣會帶來一些安全性問題。
Component
public interface IFile {
/**
* @Description: 顯示文件夾的名稱
* @param:
* @return: void
**/
public void display();
/**
* @Description: 添加
* @param: []
* @return: boolean
**/
public boolean add(IFile iFile);
/**
* @Description: 刪除
* @param: []
* @return: boolean
**/
public boolean remove(IFile iFile);
/**
* @Description: 獲得子節點
* @param: []
* @return: java.util.List<com.enjoy.cap26.IFile>
**/
public List<IFile> getChildren();
}
Leaf
/**
* @ClassName Files
* @Description TODO
* @Version 1.0
**/
public class Files implements IFile{
private String name;
public Files(String name) {
this.name = name;
}
@Override
public void display() {
System.out.println(name);
}
@Override
public boolean add(IFile iFile) {
return false;
}
@Override
public boolean remove(IFile iFile) {
return false;
}
@Override
public List<IFile> getChildren() {
return null;
}
}
Composite
/**
* @ClassName Folder
* @Description TODO
* @Version 1.0
**/
public class Folder implements IFile{
private String name;
private List<IFile> children;
public Folder(String name) {
this.name = name;
children = new ArrayList<IFile>();
}
@Override
public void display() {
System.out.println(name);
}
@Override
public boolean add(IFile iFile) {
return children.add(iFile);
}
@Override
public boolean remove(IFile iFile) {
return children.remove(iFile);
}
@Override
public List<IFile> getChildren() {
return children;
}
}
測試:
/**
* @ClassName test
* @Description TODO
* @Version 1.0
**/
public class Test {
public static void main(String[] args) {
//父節點
Folder folder = new Folder("D:");
//子節點 目錄
Folder javaFoder = new Folder("java");
//子節點 helloworld.txt
Files files = new Files("helloworld.txt");
folder.add(javaFoder);
folder.add(files);
Folder sprFoder = new Folder("spring");
Files files2 = new Files("springAop-api");
javaFoder.add(sprFoder);
javaFoder.add(files2);
//子節點 目錄
Folder stuFoder = new Folder("學習");
Files files1 = new Files("String.txt");
folder.add(stuFoder);
folder.add(files1);
displayTree(folder,0);
}
/**
* 使用遞歸
* @param iFile
* @param deep
*/
public static void displayTree(IFile iFile,int deep){
for (int i = 0; i < deep;i++){
System.out.print("--");
}
//顯示自身名稱
iFile.display();
List<IFile> children = iFile.getChildren();
for (IFile file : children) {
if( file instanceof Files){
for (int i = 0; i <= deep;i++){
System.out.print("---");
}
file.display();
}else{
displayTree(file,deep+1);
}
}
}
}
五,安全方式
安全方式:在該方式中,將管理子構件的方法移到樹枝構件中,抽象構件和樹葉構件沒有對子對象的管理方法,這樣就避免了上一種方式的安全性問題,但由於葉子和分支有不同的接口,客戶端在調用時要知道樹葉對象和樹枝對象的存在,所以失去了透明性。
Component
/**
* @ClassName Articles
* @Description 抽象構建
* @Version 1.0
**/
public interface Articles {
/**
* @Description: 計算
* @param: []
* @return: float
* @Author: wuchao
* @Date: 2020/6/26 20:31
**/
public float calculation();
/**
* @Description: 顯示
* @param: []
* @return: void
* @Author: wuchao
* @Date: 2020/6/26 20:32
**/
public void show();
}
leaf:
/**
* @ClassName Goods
* @Description 樹葉構件
* @Version 1.0
**/
public class Goods implements Articles{
private String name;
/**
* 數量
*/
private int quantity;
/**
* 單價
*/
private float unitPrice;
public Goods(String name, int quantity, float unitPrice) {
this.name = name;
this.quantity = quantity;
this.unitPrice = unitPrice;
}
@Override
public float calculation() {
return quantity*unitPrice;
}
@Override
public void show() {
System.out.println(name+"(數量:"+quantity+",單價:"+unitPrice+"元)");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public float getUnitPrice() {
return unitPrice;
}
public void setUnitPrice(float unitPrice) {
this.unitPrice = unitPrice;
}
}
Composite
/**
* @ClassName Bags
* @Description TODO
* @Version 1.0
**/
public class Bags implements Articles{
private String name;
private List<Articles> list;
public Bags(String name) {
this.name = name;
list = new ArrayList<Articles>();
}
@Override
public float calculation() {
float s=0;
for(Object obj:list)
{
s+=((Articles)obj).calculation();
}
return s;
}
@Override
public void show() {
for(Object obj:list) {
((Articles)obj).show();
}
}
/**
* 新增對象
* @param c
*/
public void add(Articles c) {
list.add(c);
}
/**
* 刪除對象
* @param c
*/
public void remove(Articles c) {
list.remove(c);
}
/**
* 獲得list
* @return
*/
public List<Articles> getChild(){
return list;
}
}
測試:
public class Test {
public static void main(String[] args) {
float s=0;
Bags BigBag,mediumBag,smallRedBag,smallWhiteBag;
Goods sp;
BigBag=new Bags("大袋子");
mediumBag=new Bags("中袋子");
smallRedBag=new Bags("紅色小袋子");
smallWhiteBag=new Bags("白色小袋子");
sp=new Goods("婺源特產",2,7.9f);
smallRedBag.add(sp);
sp=new Goods("婺源地圖",1,9.9f);
smallRedBag.add(sp);
sp=new Goods("韶關香菇",2,68);
smallWhiteBag.add(sp);
sp=new Goods("韶關紅茶",3,180);
smallWhiteBag.add(sp);
sp=new Goods("景德鎮瓷器",1,380);
mediumBag.add(sp);
mediumBag.add(smallRedBag);
sp=new Goods("李寧牌運動鞋",1,198);
BigBag.add(sp);
BigBag.add(smallWhiteBag);
BigBag.add(mediumBag);
System.out.println("您選購的商品有:");
BigBag.show();
s=BigBag.calculation();
System.out.println("要支付的總價是:"+s+"元");
}
}
六,組合模式的應用場景
- 在需要表示一個對象整體與部分的層次結構的場合。
- 要求對用戶隱藏組合對象與單個對象的不同,用戶可以用統一的接口使用組合結構中的所有對象的場合。