黄色网址大全免费-黄色网址你懂得-黄色网址你懂的-黄色网址有那些-免费超爽视频-免费大片黄国产在线观看

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動力節(jié)點LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 hot資訊 設計模式中的組合模式詳解

設計模式中的組合模式詳解

更新時間:2022-10-11 10:10:49 來源:動力節(jié)點 瀏覽999次

設計模式中的組合模式是什么?小編來告訴大家。將一組對象組織(Compose)成樹形結構,以表示一種“部分 - 整體”的層次結構。組合讓客戶端可以統一單個對象和組合對象的處理邏輯。接下來,對于組合模式,舉個例子來給你解釋一下。

假設我們有這樣一個需求:設計一個類來表示文件系統中的目錄,能方便地實現下面這些功能:

動態(tài)地添加、刪除某個目錄下的子目錄或文件;

統計指定目錄下的文件個數;

統計指定目錄下的文件總大小。

這里給出了這個類的骨架代碼,如下所示。其中的核心邏輯并未實現,你可以試著自己去補充完整,再來看我的講解。在下面的代碼實現中,我們把文件和目錄統一用 FileSystemNode 類來表示,并且通過File類屬性來區(qū)分。

public class FileSystemNode {
  private String path;
  private boolean isFile;
  private List<FileSystemNode> subNodes = new ArrayList<>();
  public FileSystemNode(String path, boolean isFile) {
    this.path = path;
    this.isFile = isFile;
  }
  public int countNumOfFiles() {
    // TODO:...
  }
  public long countSizeOfFiles() {
    // TODO:...
  }
  public String getPath() {
    return path;
  }
  public void addSubNode(FileSystemNode fileOrDir) {
    subNodes.add(fileOrDir);
  }
  public void removeSubNode(FileSystemNode fileOrDir) {
    int size = subNodes.size();
    int i = 0;
    for (; i < size; ++i) {
      if (subNodes.get(i).getPath().equalsIgnoreCase(fileOrDir.getPath())) {
        break;
      }
    }
    if (i < size) {
      subNodes.remove(i);
    }
  }
}

想要補全其中的 countNumOfFiles() 和 countSizeOfFiles() 這兩個函數,并不是件難事,實際上這就是樹上的遞歸遍歷算法。對于文件,我們直接返回文件的個數(返回 1)或大小。對于目錄,我們遍歷目錄中每個子目錄或者文件,遞歸計算它們的個數或大小,然后求和,就是這個目錄下的文件個數和文件大小。

public int countNumOfFiles() {
    if (isFile) {
        return 1;
    }
    int numOfFiles = 0;
    for (FileSystemNode fileOrDir : subNodes) {
        numOfFiles += fileOrDir.countNumOfFiles();
    }
    return numOfFiles;
}
public long countSizeOfFiles() {
    if (isFile) {
        File file = new File(path);
        if (!file.exists()) return 0;
        return file.length();
    }
    long sizeofFiles = 0;
    for (FileSystemNode fileOrDir : subNodes) {
         sizeofFiles += fileOrDir.countSizeOfFiles();
    }
    return sizeofFiles;

單純從功能實現角度來說,上面的代碼沒有問題,已經實現了我們想要的功能。但是,如果我們開發(fā)的是一個大型系統,從擴展性(文件或目錄可能會對應不同的操作)、業(yè)務建模(文件和目錄從業(yè)務上是兩個概念)、代碼的可讀性(文件和目錄區(qū)分對待更加符合人們對業(yè)務的認知)的角度來說,我們最好對文件和目錄進行區(qū)分設計,定義為 File 和 Directory 兩個類。

按照這個設計思路,我們對代碼進行重構。重構之后的代碼如下所示:

public abstract class FileSystemNode {
  protected String path;
  public FileSystemNode(String path) {
    this.path = path;
  }
  public abstract int countNumOfFiles();
  public abstract long countSizeOfFiles();
    public String getPath() {
    return path;
  }
}
public class File extends FileSystemNode {
  public File(String path) {
    super(path);
  }
  @Override
  public int countNumOfFiles() {
    return 1;
  }
  @Override
  public long countSizeOfFiles() {
    java.io.File file = new java.io.File(path);
    if (!file.exists()) return 0;
    return file.length();
  }
}
public class Directory extends FileSystemNode {
  private List<FileSystemNode> subNodes = new ArrayList<>();
  public Directory(String path) {
    super(path);
  }
  @Override
  public int countNumOfFiles() {
    int numOfFiles = 0;
    for (FileSystemNode fileOrDir : subNodes) {
      numOfFiles += fileOrDir.countNumOfFiles();
    }
    return numOfFiles;
  }
  @Override
  public long countSizeOfFiles() {
    long sizeofFiles = 0;
    for (FileSystemNode fileOrDir : subNodes) {
      sizeofFiles += fileOrDir.countSizeOfFiles();
    }
    return sizeofFiles;
  }
  public void addSubNode(FileSystemNode fileOrDir) {
    subNodes.add(fileOrDir);
  }
  public void removeSubNode(FileSystemNode fileOrDir) {
    int size = subNodes.size();
    int i = 0;
    for (; i < size; ++i) {
      if (subNodes.get(i).getPath().equalsIgnoreCase(fileOrDir.getPath())) {
        break;
      }
    }
    if (i < size) {
      subNodes.remove(i);
    }
  }
}

文件和目錄類都設計好了,我們來看,如何用它們來表示一個文件系統中的目錄樹結構。具體的代碼示例如下所示:

public class Demo {
  public static void main(String[] args) {
    /**
     * /
     *
     * <p>/wz/
     *
     * <p>/wz/a.txt
     *
     * <p>/wz/b.txt
     *
     * <p>/wz/movies/
     *
     * <p>/wz/movies/c.avi
     *
     * <p>/xzg/
     *
     * <p>/xzg/docs/
     *
     * <p>/xzg/docs/d.txt
     */
    Directory fileSystemTree = new Directory("/");
    Directory node_wz = new Directory("/wz/");
    Directory node_xzg = new Directory("/xzg/");
    fileSystemTree.addSubNode(node_wz);
    fileSystemTree.addSubNode(node_xzg);    
    File node_wz_a = new File("/wz/a.txt");
    File node_wz_b = new File("/wz/b.txt");
    Directory node_wz_movies = new Directory("/wz/movies/");
    node_wz.addSubNode(node_wz_a);
    node_wz.addSubNode(node_wz_b);
    node_wz.addSubNode(node_wz_movies);    
    File node_wz_movies_c = new File("/wz/movies/c.avi");
    node_wz_movies.addSubNode(node_wz_movies_c);    
    Directory node_xzg_docs = new Directory("/xzg/docs/");
    node_xzg.addSubNode(node_xzg_docs);    
    File node_xzg_docs_d = new File("/xzg/docs/d.txt");
    node_xzg_docs.addSubNode(node_xzg_docs_d);    
    System.out.println("/ files num:" + fileSystemTree.countNumOfFiles());
    System.out.println("/wz/ files num:" + node_wz.countNumOfFiles());
  }
}

我們對照著這個例子,再重新看一下組合模式的定義:“將一組對象(文件和目錄)組織成樹形結構,以表示一種‘部分 - 整體’的層次結構(目錄與子目錄的嵌套結構)。組合模式讓客戶端可以統一單個對象(文件)和組合對象(目錄)的處理邏輯(遞歸遍歷)。”

實際上,剛才講的這種組合模式的設計思路,與其說是一種設計模式,倒不如說是對業(yè)務場景的一種數據結構和算法的抽象。其中,數據可以表示成樹這種數據結構,業(yè)務需求可以通過在樹上的遞歸遍歷算法來實現。

組合模式的應用場景舉例

剛剛我們講了文件系統的例子,對于組合模式,我這里再舉一個例子。搞懂了這兩個例子,你基本上就算掌握了組合模式。在實際的項目中,遇到類似的可以表示成樹形結構的業(yè)務場景,你只要“照葫蘆畫瓢”去設計就可以了。

假設我們在開發(fā)一個 OA 系統(辦公自動化系統)。公司的組織結構包含部門和員工兩種數據類型。其中,部門又可以包含子部門和員工。在數據庫中的表結構如下所示:

我們希望在內存中構建整個公司的人員架構圖(部門、子部門、員工的隸屬關系),并且提供接口計算出部門的薪資成本(隸屬于這個部門的所有員工的薪資和)。

部門包含子部門和員工,這是一種嵌套結構,可以表示成樹這種數據結構。計算每個部門的薪資開支這樣一個需求,也可以通過在樹上的遍歷算法來實現。所以,從這個角度來看,這個應用場景可以使用組合模式來設計和實現。

這個例子的代碼結構跟上一個例子的很相似,代碼實現我直接貼在了下面,你可以對比著看一下。其中,HumanResource 是部門類(Department)和員工類(Employee)抽象出來的父類,為的是能統一薪資的處理邏輯。Demo 中的代碼負責從數據庫中讀取數據并在內存中構建組織架構圖。

public  abstract  class  HumanResource  {
  protected  long id;
  protected  double salary;
  public  HumanResource(long id)  {
    this.id = id;
  }
  public  long  getId()  {
    return id;
  }
  public  abstract  double  calculateSalary();

}
public  class  Employee  extends  HumanResource  {
  public  Employee(long id, double salary)  {
    super(id);
    this.salary = salary;
  }
  @Override
  public  double  calculateSalary()  {
    return salary;
  }
}
public  class  Department  extends  HumanResource  {
  private List<HumanResource> subNodes = new ArrayList<>();
  public  Department(long id)  {
    super(id);
  }
  @Override
  public  double  calculateSalary()  {
    double totalSalary = 0;
    for (HumanResource hr : subNodes) {
      totalSalary += hr.calculateSalary();
    }
    this.salary = totalSalary;
    return totalSalary;
  }
  public  void  addSubNode(HumanResource hr)  {
    subNodes.add(hr);
  }
}
// 構建組織架構的代碼
public  class  Demo  {
  private  static  final  long ORGANIZATION\_ROOT\_ID = 1001;
  private DepartmentRepo departmentRepo; // 依賴注入
  private EmployeeRepo employeeRepo; // 依賴注入
  public  void  buildOrganization()  {
    Department rootDepartment = new Department(ORGANIZATION\_ROOT\_ID);
    buildOrganization(rootDepartment);
  }
  private  void  buildOrganization(Department department)  {
    List<Long> subDepartmentIds = departmentRepo.getSubDepartmentIds(department.getId());
    for (Long subDepartmentId : subDepartmentIds) {
      Department subDepartment = new Department(subDepartmentId);
      department.addSubNode(subDepartment);
      buildOrganization(subDepartment);
    }
    List<Long> employeeIds = employeeRepo.getDepartmentEmployeeIds(department.getId());
    for (Long employeeId : employeeIds) {
      double salary = employeeRepo.getEmployeeSalary(employeeId);
      department.addSubNode(new Employee(employeeId, salary));
    }
  }
}

我們再拿組合模式的定義跟這個例子對照一下:“將一組對象(員工和部門)組織成樹形結構,以表示一種‘部分 - 整體’的層次結構(部門與子部門的嵌套結構)。組合模式讓客戶端可以統一單個對象(員工)和組合對象(部門)的處理邏輯(遞歸遍歷)。

提交申請后,顧問老師會電話與您溝通安排學習

免費課程推薦 >>
技術文檔推薦 >>
主站蜘蛛池模板: 日本中文字幕永久在线 | 月婷婷色狠狠 | 欧美色成人tv在线播放 | 新版天堂中文资源官网 | 草草视频在线播放 | 色黄网站aaaaaa级毛片 | 钻石午夜影院 | 免费看的一级片 | 亚洲伊人久久综合影院2021 | 伊人热 | 亚洲 欧美 在线观看 | 在线亚洲欧美性天天影院 | 欧美人妖xxx | 国产一区曰韩二区欧美三区 | 天天爽夜夜爽免费看 | 欧美精品1区 | 男女交性过程视频无遮挡在线 | 亚洲精品tv久久久久久久久 | 草草视频免费观看 | 被黄漫网站视频在线观看 | jizzzz亚洲丰满xxxxⅹ | 成人短视频在线观看免费 | 日韩一区在线视频 | 黄 色 免费网 站 成 人 | 免费在线a | 国产精品久久久久久久久久直 | 一级毛片免费视频网站 | 在线播放 你懂的 | 中文字幕日本一区 | 国产成人精品三级91在线影院 | 亚洲一二三区在线观看 | 网站在线观看你懂的 | 国产精品揄拍一区二区 | 午夜爽爽爽 | 免费大黄网站 | xx性动漫xx无尽xx老师 | 色天使亚洲综合在线观看 | 久久久精品午夜免费不卡 | 久久综合九色综合97_ 久久久 | 欧美激情一区二区三区在线 | 久久精品中文字幕第一页 |