日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

设计模式之组合模式(Composite)

發布時間:2025/3/17 asp.net 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 设计模式之组合模式(Composite) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.引言

在學習JUnit的時候,看到一段話“JUnit框架是一個典型的Composite模式:TestSuite可以容納任何派生自Test的對象;當調用TestSuite對象的run()方法是,會遍歷自己容納的對象,逐個調用它們的run()方法”。就來學習什么是組合模式。

2.應用實例

在實現跟商品有關的應用系統的時候,一個很常見的功能就是商品類別樹的管理,比如有以下的商品類別樹:

——————————————————————————————————

-服裝
  -男裝
    -襯衣
    -夾克
  -女裝
    -裙子
    -套裝

——————————————————————————————————

通過上面的商品類別樹我們可以發現商品類別樹有兩種類型的節點,分別是葉子節點(襯衣,夾克)和組合節點(服裝,男裝,女裝)。組合節點中可以包含其他的組合節點或者葉子節點,而葉子節點不能。

給出一個簡單的管理商品類別樹的實例代碼。

2.1不使用組合模式的解決方案

組合節點Composite

View Code package edu.sjtu.erplab.designpattern.composite.exp1;

import java.util.ArrayList;
import java.util.Collection;

public class Composite {
private Collection<Composite> childComposite=new ArrayList<Composite>();
private Collection<Leaf> childLeaf=new ArrayList<Leaf>();
private String name="";
public Composite(String name)
{
this.name=name;
}
//向組合對象中加入其他組合對象
public void addComposite(Composite c)
{
this.childComposite.add(c);
}
//向組合對象加入其他葉子對象
public void addLeaf(Leaf l)
{
this.childLeaf.add(l);
}

//輸出組合對象結構
public void printStruct(String preStr)
{
System.out.println(preStr+"-"+name);
preStr+=" ";
for(Leaf leaf:childLeaf)
{
leaf.printStruct(preStr);
}
for(Composite composite:childComposite)
{
composite.printStruct(preStr);
}

}
}

葉子節點

View Code package edu.sjtu.erplab.designpattern.composite.exp1;

public class Leaf {
private String name="";
public Leaf(String name){
this.name=name;
}
public void printStruct(String preStr)
{
System.out.println(preStr+"-"+name);
}

}

客戶端Client

View Code package edu.sjtu.erplab.designpattern.composite.exp1;

public class Client {
public static void main(String args[])
{
//定義組合對象
Composite root=new Composite("服裝");
Composite c1=new Composite("男裝");
Composite c2=new Composite("女裝");

//定義葉子對象
Leaf l1=new Leaf("襯衣");
Leaf l2=new Leaf("夾克");
Leaf l3=new Leaf("裙子");
Leaf l4=new Leaf("套裝");

//按照樹的結構來組合對象
root.addComposite(c1);
root.addComposite(c2);
c1.addLeaf(l1);
c1.addLeaf(l2);
c2.addLeaf(l3);
c2.addLeaf(l4);

root.printStruct("");

}

}

運行結果就是應用實例中顯示的商品樹形結構。

上述解決方案存在的問題:

雖然實現了要求的功能,但是有一個明顯的問題:那就是必須區分組合對象和葉子對象,并進行區別對待,比如在Composite(addComposite方法和addLeaf方法)和Client(定義Composite對象和定義Leaf對象)里面,都需要去區別對待這兩種對象。區別對待組合對象與葉子對象不但讓程序更加復雜,還對功能的擴展帶了了不便。用戶不希望區別對待這兩類對象。

2.2使用組合模式的解決方案

組合模式通過引入一個抽象的組件對象,作為組合對象和葉子對象的父對象,這樣就把組合對象和葉子對象統一起來了,用戶使用的時候,始終是在操作組件對象,而不再去區分是在操作組合對象還是葉子對象。

組合模式的關鍵就在于這個抽象類,這個抽象類既可以代表葉子對象,也可以代表組合對象,這樣用戶在操作的時候,對葉子對象和組合對象的使用就具有了一致性。

組件對象Component

View Code package edu.sjtu.erplab.designpattern.composite.exp2;

public abstract class Component {

public abstract void printStruct(String preStr);

//透明性
public void addChild(Component child){
throw new UnsupportedOperationException("對象不支持這個功能");
}

public void removeChild(Component child){
throw new UnsupportedOperationException("對象不支持這個功能");
}

public Component getChild(Component child){
throw new UnsupportedOperationException("對象不支持這個功能");
}

}

組合對象Composite

View Code package edu.sjtu.erplab.designpattern.composite.exp2;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Composite extends Component {

private List<Component> childComponents = null;
private String name = "";

public Composite(String name)
{
this.name=name;
}

@Override
public void addChild(Component child) {
// TODO Auto-generated method stub
if (childComponents == null) {
childComponents = new ArrayList<Component>();
}
childComponents.add(child);
}

@Override
public void removeChild(Component child) {
// TODO Auto-generated method stub
super.removeChild(child);

}

@Override
public Component getChild(Component child) {
// TODO Auto-generated method stub
return super.getChild(child);
}


public void printStruct(String preStr) {
System.out.println(preStr + "-" + name);
if (this.childComponents != null) {
preStr += " ";
for (Component c : childComponents) {
c.printStruct(preStr);
}
}
}

}

葉子對象Leaf

View Code package edu.sjtu.erplab.designpattern.composite.exp2;

public class Leaf extends Component {
private String name="";
public Leaf(String name){
this.name=name;
}

//必須實現父類的抽象方法
public void printStruct(String preStr)
{
System.out.println(preStr+"-"+name);
}

}

客戶端

View Code package edu.sjtu.erplab.designpattern.composite.exp2;

public class Client {
public static void main(String args[])
{
//定義組合對象
Component root=new Composite("服裝");
Component c1=new Composite("男裝");
Component c2=new Composite("女裝");

//定義葉子對象
Component l1=new Leaf("襯衣");
Component l2=new Leaf("夾克");
Component l3=new Leaf("裙子");
Component l4=new Leaf("套裝");

//按照樹的結構來組合對象
root.addChild(c1);
root.addChild(c2);
c1.addChild(l1);
c1.addChild(l2);
c2.addChild(l3);
c2.addChild(l4);

root.printStruct("");

}

}

程序架構如下圖所示。這樣的架構實現了用戶的透明訪問。

3.透明性與安全性的權衡考慮

如上圖所示,在Component組件中定義了操作組合節點的方法addChild,removeChild等,這些方法被Leaf繼承,因此Leaf也能夠調用,但是葉子節點是不能進行增加子節點和刪除子節點的。這樣就存在安全性的問題。

基于安全性考慮的組合模式的解決方案

組件節點Component

View Code package edu.sjtu.erplab.designpattern.composite.exp3;

public abstract class Component {

public abstract void printStruct(String preStr);

}

組合節點Composite和葉子節點Leaf沒有改變

客戶端發生改變,需要區分組合節點和葉子節點,這個跟第一個代碼實例中類似。

View Code package edu.sjtu.erplab.designpattern.composite.exp3;

public class Client {
public static void main(String args[])
{
//定義組合對象
Composite root=new Composite("服裝");
Composite c1=new Composite("男裝");
Composite c2=new Composite("女裝");

//定義葉子對象
Leaf l1=new Leaf("襯衣");
Leaf l2=new Leaf("夾克");
Leaf l3=new Leaf("裙子");
Leaf l4=new Leaf("套裝");

//按照樹的結構來組合對象
root.addChild(c1);
root.addChild(c2);
c1.addChild(l1);
c1.addChild(l2);
c2.addChild(l3);
c2.addChild(l4);

root.printStruct("");

}

}

上述實例的結構如下圖所示:

透明性組合模式與安全性組合模式的選擇:

對于組合模式,在安全性和透明性上,會更加看重透明性,畢竟組合模式的功能就是讓客戶端對葉子對象和組合對象的使用具有一致性。

4.父組件引用

在上面的示例中,都是在父組件對象中,保存有子組件的引用,也就是說都是從父到子的引用,本節討論一下子組件對象到父組件對象的引用,在實際開發過程中也非常有用,比如可以實現如下功能:

  • 刪除某個商品的類別, 如果是子對象,那么直接刪除,如果是組合對象,那么將組合對象下的所有子對象的層級提高一層。
  • 調整商品類別。
  • 要實現上述功能, 一個較為簡單的方案就是在保持從父組件到子組件引用的基礎上,再增加保持從子組件到父組件的引用,這樣在刪除一個組件對象或者是調整一個組件對象的時候,可以通過調整父組件的引用來實現,可以大大簡化實現。

    實例說明如下:

    組件對象Component

    View Code package edu.sjtu.erplab.designpattern.composite.exp4;

    import java.util.List;

    public abstract class Component {

    private Component parent=null;

    //獲取某個組件的所有子對象
    public List<Component> getChildren()
    {
    throw new UnsupportedOperationException("對象不支持這個功能");
    }
    //獲取父對象
    public Component getParent() {
    return parent;
    }

    public void setParent(Component parent) {
    this.parent = parent;
    }

    public abstract void printStruct(String preStr);

    public void addChild(Component child){
    throw new UnsupportedOperationException("對象不支持這個功能");
    }

    public void removeChild(Component child){
    throw new UnsupportedOperationException("對象不支持這個功能");
    }

    public Component getChild(Component child){
    throw new UnsupportedOperationException("對象不支持這個功能");
    }

    }

    組合對象Composite

    View Code package edu.sjtu.erplab.designpattern.composite.exp4;

    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;

    public class Composite extends Component {

    private List<Component> childComponents = null;
    private String name = "";

    public Composite(String name)
    {
    this.name=name;
    }

    public void printStruct(String preStr) {
    System.out.println(preStr + "-" + name);
    if (this.childComponents != null) {
    preStr += " ";
    for (Component c : childComponents) {
    c.printStruct(preStr);
    }
    }
    }

    /**
    * 添加子組件
    * child為具體的子組件
    * 為child設置父組件。setParent
    */
    @Override
    public void addChild(Component child) {
    if (childComponents == null) {
    childComponents = new ArrayList<Component>();
    }
    childComponents.add(child);
    //添加對父組件的引用
    child.setParent(this);

    }

    /**
    * 刪除子組件
    */
    @Override
    public void removeChild(Component child) {
    if(childComponents!=null)
    {
    int idx=childComponents.indexOf(child);
    if(idx!=-1)
    {
    for(Component c:child.getChildren())//獲取被刪除組件的所有子組件
    {
    c.setParent(this);//設置父類別
    childComponents.add(c);//更改結構,添加子類別
    }
    childComponents.remove(idx);
    }
    }

    }

    @Override
    public List<Component> getChildren()
    {
    return childComponents;
    }
    }

    葉子節點沒有變化,客戶端有所改變

    View Code package edu.sjtu.erplab.designpattern.composite.exp4;

    public class Client {
    public static void main(String args[])
    {
    //定義組合對象
    Component root=new Composite("服裝");
    Component c1=new Composite("男裝");
    Component c2=new Composite("女裝");

    //定義葉子對象
    Component l1=new Leaf("襯衣");
    Component l2=new Leaf("夾克");
    Component l3=new Leaf("裙子");
    Component l4=new Leaf("套裝");

    //按照樹的結構來組合對象
    root.addChild(c1);
    root.addChild(c2);
    c1.addChild(l1);
    c1.addChild(l2);
    c2.addChild(l3);
    c2.addChild(l4);

    root.printStruct("");
    System.out.println("---------------------------------");
    root.removeChild(c1);
    root.printStruct("");
    }

    }

    程序運行結果:

    ——————————————————————————

    -服裝
      -男裝
        -襯衣
        -夾克
      -女裝
        -裙子
        -套裝
    ---------------------------------
    -服裝
      -女裝
        -裙子
        -套裝
      -襯衣
      -夾克

    ——————————————————————

    程序架構結構圖如下圖所示:

    5組合模式的優缺點及適用環境

    優點:

  • 定義了包含基本對象和組合對象的層次結構
  • 統一了組合對象和葉子對象
  • 簡化了客戶端調用
  • 更容易擴展
  • 缺點:

  • 很難閑置組合中的組件類型
  • 適用環境

  • 如果你想表示對象的部分-整體層次結構,可以選用組合模式,把整體和部分的操作統一起來,是的層次結構實現更簡單,從外部來使用這個層次結構也更加容易。
  • 如果你希望統一得使用組合結構中的所有對象,可以選用組合模式,這正是組合模式提供的主要功能。







  • 轉載于:https://www.cnblogs.com/xwdreamer/archive/2012/03/29/2424034.html

    總結

    以上是生活随笔為你收集整理的设计模式之组合模式(Composite)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。