设计格局,结构型形式

By admin in 4858.com on 2019年10月6日

那篇主要描述设计形式中的组合格局。组合形式又叫部分完全方式,是用来把一组平时的靶子当做三个纯净的对象。组合方式依靠树形结构来构成对象,用来代表部分以及完整档期的顺序。那连串型的设计格局属于结构型情势,它创造了对象组的树形结构。树形结构在软件中历历可知,比如操作系统中的目录结构、APP中的菜单、办公系统中的公司集体结构等等。接下来看看组合形式的结构图

组成多少个指标产生树形结构以表示具有“全体—部分”关系的等级次序结构。组合情势对单个对象(即叶子对象)和烧结对象(即容器对象)的运用全数一致性,组合方式又足以称作“全体—部分”(Part-Whole)形式

定义

  组合方式(Composite
Pattern):组合多个对象形成树形结构以表示全部“整体—部分”关系的档期的顺序结构。组合情势对单个对象(即叶子对象)和重组对象(即容器对象)的选用具备一致性,组合情势又有啥不可称作“全体—部分”(Part-Whole)格局,它是一种对象结构型模式。

【学习难度:★★★☆☆,使用成效:★★★★☆】
向来出处:http://woquanke.com/books/gof/
梳理和上学:https://github.com/BruceOuyang/boy-design-pattern
简书日期: 2018/03/12
简书首页:

4858.com 1此间写图片描述

类型

结构型

结构图

4858.com 2

要素:

Component(抽象构件):它能够是接口或抽象类,为叶子构件和容器构件对象注明接口,在该角色中得以蕴含全数子类共有行为的宣示和兑现。在空设想件中定义了拜访及管制它的子构件的艺术,如扩展子构件、删除子构件、获取子构件等。

Leaf(叶子构件):它在结合结构中意味叶子节点目的,叶子节点没有子节点,它达成了在抽象构件中定义的行为。对于那多少个访谈及处理子构件的点子,能够通过特别等措施进行拍卖。

Composite(容器构件):它在整合结构中代表容器节点目的,容器节点包蕴子节点,其子节点能够是卡片节点,也足以是容器节点,它提供二个会合用于存款和储蓄子节点,达成了在架空构件中定义的展现,满含那些访谈及管理子构件的法子,在其业务方法中可以递归调用其子节点的专门的学业方法。
整合形式的主要:概念了一个抽象构件类,它不只能够代表叶子,又能够表示容器,而顾客端针对该抽象构件类进行编程,无须知道它毕竟意味着的是卡牌照旧容器,能够对其开展集结管理

abstract class Component {  
    public abstract void add(Component c); //增加成员  
    public abstract void remove(Component c); //删除成员  
    public abstract Component getChild(int i); //获取成员  
    public abstract void operation();  //业务方法  
}  

class Leaf extends Component {  
    public void add(Component c) {   
        //异常处理或错误提示   
    }     

    public void remove(Component c) {   
        //异常处理或错误提示   
    }  

    public Component getChild(int i) {   
        //异常处理或错误提示  
        return null;   
    }  

    public void operation() {  
        //叶子构件具体业务方法的实现  
    }   
}  

class Composite extends Component {  
    private ArrayList<Component> list = new ArrayList<Component>();  

    public void add(Component c) {  
        list.add(c);  
    }  

    public void remove(Component c) {  
        list.remove(c);  
    }  

    public Component getChild(int i) {  
        return (Component)list.get(i);  
    }  

    public void operation() {  
        //容器构件具体业务方法的实现  
        //递归调用成员构件的业务方法  
        for(Object obj:list) {  
            ((Component)obj).operation();  
        }  
    }     
}  

树形结构的拍卖——组合格局(一)

树形结构在软件中历历可知,举个例子操作系统中的目录结构、APP中的菜单、办公系统中的集团团体结构等等,怎么样利用面向对象的点子来拍卖这种树形结构是整合情势必要解决的题目,组合方式通过一种高超的技术方案使得顾客能够一致性地处理任何树形结构依旧树形结构的一片段,也能够一致性地拍卖树形结构中的叶子节点(不包涵子节点的节点)和容器节点(包括子节点的节点)。上面将学习这种用于拍卖树形结构的结缘形式。

11.1 设计杀毒软件的架构

Sunny软件商城欲开垦叁个杀毒(AntiVirus)软件,该软件不仅能对某些文件夹(Folder)杀毒,也能够对有些钦点的文书(File)举行杀毒。该杀毒软件还足以依附种种文件的风味,为不一样品种的文书提供分裂的杀毒形式,比方图像文件(ImageFile)和文书文件(TextFile)的杀毒形式就有所差异。现供给提供该杀毒软件的总体框架解决方案。

在介绍萨妮集团开垦职员建议的开端实施方案在此以前,我们先来深入分析一下操作系统中的文件目录结构,比如在Windows操作系统中,存在如图11-1所示目录结构:

4858.com 3

图11-1 Windows目录结构

图11-1得以简化为如图11-2所示树形目录结构:

4858.com 4

图11-2 树形目录结构暗暗提示图

咱俩得以看出,在图11-第22中学包蕴文件(乌紫节点)和文书夹(紫罗兰色节点)两类差异的要素,个中在文件夹中能够包蕴文件,还足以承袭包罗子文件夹,可是在文书中不可能再富含子文件或许子文件夹。在此,大家得以称文件夹为容器(Container),而各异连串的各类文件是其成员,也称为叶子(Leaf),三个文件夹也得以视作另三个更加大的文件夹的积极分子。就算大家前天要对某三个文书夹举行操作,如查找文件,那么供给对点名的文件夹进行遍历,如若存在子文件夹则打开其子文件夹继续遍历,如若是文本则判别之后回来找寻结果。

Sunny软件公司的开辟人士通过解析,决定动用面向对象的秘诀来完成对文本和文件夹的操作,定义了之类图像文件类ImageFile、文本文件类TextFile和文件夹类Folder:

//为了突出核心框架代码,我们对杀毒过程的实现进行了大量简化 
import java.util.*; 

//图像文件类 
class ImageFile { 
private String name; 

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

public void killVirus() { 
//简化代码,模拟杀毒 
System.out.println("----对图像文件'" + name + "'进行杀毒"); 
} 
} 

//文本文件类 
class TextFile { 
private String name; 

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

public void killVirus() { 
//简化代码,模拟杀毒 
System.out.println("----对文本文件'" + name + "'进行杀毒"); 
} 
} 

//文件夹类 
class Folder { 
private String name; 
//定义集合folderList,用于存储Folder类型的成员 
private ArrayList<Folder> folderList = new ArrayList<Folder>(); 
//定义集合imageList,用于存储ImageFile类型的成员 
private ArrayList<ImageFile> imageList = new ArrayList<ImageFile>(); 
//定义集合textList,用于存储TextFile类型的成员 
private ArrayList<TextFile> textList = new ArrayList<TextFile>(); 

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

//增加新的Folder类型的成员 
public void addFolder(Folder f) { 
folderList.add(f); 
} 

//增加新的ImageFile类型的成员 
public void addImageFile(ImageFile image) { 
imageList.add(image); 
} 

//增加新的TextFile类型的成员 
public void addTextFile(TextFile text) { 
textList.add(text); 
} 

//需提供三个不同的方法removeFolder()、removeImageFile()和removeTextFile()来删除成员,代码省略 

//需提供三个不同的方法getChildFolder(int i)、getChildImageFile(int i)和getChildTextFile(int i)来获取成员,代码省略 

public void killVirus() { 
System.out.println("****对文件夹'" + name + "'进行杀毒"); //模拟杀毒 

//如果是Folder类型的成员,递归调用Folder的killVirus()方法 
for(Object obj : folderList) { 
((Folder)obj).killVirus(); 
} 

//如果是ImageFile类型的成员,调用ImageFile的killVirus()方法 
for(Object obj : imageList) { 
((ImageFile)obj).killVirus(); 
} 

//如果是TextFile类型的成员,调用TextFile的killVirus()方法 
for(Object obj : textList) { 
((TextFile)obj).killVirus(); 
} 
} 
}

编写制定如下客商端测量检验代码进行测量试验:

class Client { 
public static void main(String args[]) { 
Folder folder1,folder2,folder3; 
folder1 = new Folder("Sunny的资料"); 
folder2 = new Folder("图像文件"); 
folder3 = new Folder("文本文件"); 

ImageFile image1,image2; 
image1 = new ImageFile("小龙女.jpg"); 
image2 = new ImageFile("张无忌.gif"); 

TextFile text1,text2; 
text1 = new TextFile("九阴真经.txt"); 
text2 = new TextFile("葵花宝典.doc"); 

folder2.addImageFile(image1); 
folder2.addImageFile(image2); 
folder3.addTextFile(text1); 
folder3.addTextFile(text2); 
folder1.addFolder(folder2); 
folder1.addFolder(folder3); 

folder1.killVirus(); 
} 
}

编写翻译并运转程序,输出结果如下:

****对文件夹'Sunny的资料'进行杀毒
****对文件夹'图像文件'进行杀毒
----对图像文件'小龙女.jpg'进行杀毒
----对图像文件'张无忌.gif'进行杀毒
****对文件夹'文本文件'进行杀毒
----对文本文件'九阴真经.txt'进行杀毒
----对文本文件'葵花宝典.doc'进行杀毒

Sunny集团开垦职员“成功”落成了杀毒软件的框架设计,但透过精心深入分析,开采该施工方案存在如下难点:

(1)
文件夹类Folder的筹算和兑现都特别复杂,须求定义三个聚众存款和储蓄分裂类型的成员,况且亟需针对差异的分子提供扩充、删除和获得等管理和访谈成员的情势,存在大气的冗余代码,系统爱戴比较困难;

(2)
由于系统尚未提供抽象层,客商端代码必需有分别地看待当做容器的公文夹Folder和担当叶子的ImageFile和TextFile,不能统一对它们举办拍卖;

(3)
系统的贯虱穿杨和可扩展性差,如若要求追加新的项目标叶子和容器都急需对本来代码举办改造,例如假设须要在系统中追加一种新类型的录制文件VideoFile,则必需修改Folder类的源代码,不然不恐怕在文件夹中加多摄像文件。

面前境遇上述难点,萨妮软件集团的开采职员该怎么来化解?那就必要用到本章将在介绍的结合格局,组合格局为管理树形结构提供了一种比较完善的实施方案,它汇报了什么将容器和叶子进行递归组合,使得客户在使用时不用对它们实行区分,能够一直以来地对待容器和叶子。

在结合情势组织图中含有如下几个剧中人物:

简介

  • 组合情势的严重性是概念了二个浮泛构件类,它不只能够代表叶子,又可以表示容器,而顾客端针对该抽象构件类进行编程,无须知道它毕竟意味着的是卡片依然容器,能够对其开展联合处理。
  • 何况容器对象与虚无构件类之间还树立多个凑合关联关系,在容器对象中不仅可以够分包叶子,也足以包罗容器,以此完结递归组合,形成一个树形结构。

设计格局,结构型形式。示例

  Sunny软件百货店欲开荒二个杀毒(AntiVirus)软件,该软件不仅能够对有个别文件夹(Folder)杀毒,也可以对有个别钦点的公文(File)实行杀毒。该杀毒软件还是能够依附种种文件的特征,为区别连串的公文提供分化的杀毒方式,例如图像文件(ImageFile)和文书文件(TextFile)的杀毒情势就颇有差异。现须求提供该杀毒软件的完整框架施工方案。

4858.com 5

//为了突出核心框架代码,我们对杀毒过程的实现进行了大量简化  
import java.util.*;  

//图像文件类  
class ImageFile {  
    private String name;  

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

    public void killVirus() {  
        //简化代码,模拟杀毒  
        System.out.println("----对图像文件'" + name + "'进行杀毒");  
    }  
}  

//文本文件类  
class TextFile {  
    private String name;  

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

    public void killVirus() {  
        //简化代码,模拟杀毒  
        System.out.println("----对文本文件'" + name + "'进行杀毒");  
    }  
}  

//文件夹类  
class Folder {  
    private String name;  
    //定义集合folderList,用于存储Folder类型的成员  
    private ArrayList<Folder> folderList = new ArrayList<Folder>();  
    //定义集合imageList,用于存储ImageFile类型的成员  
    private ArrayList<ImageFile> imageList = new ArrayList<ImageFile>();  
    //定义集合textList,用于存储TextFile类型的成员  
    private ArrayList<TextFile> textList = new ArrayList<TextFile>();  

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

    //增加新的Folder类型的成员  
    public void addFolder(Folder f) {  
        folderList.add(f);  
    }  

    //增加新的ImageFile类型的成员  
    public void addImageFile(ImageFile image) {  
        imageList.add(image);  
    }  

    //增加新的TextFile类型的成员  
    public void addTextFile(TextFile text) {  
        textList.add(text);  
    }  

    //需提供三个不同的方法removeFolder()、removeImageFile()和removeTextFile()来删除成员,代码省略  

    //需提供三个不同的方法getChildFolder(int i)、getChildImageFile(int i)和getChildTextFile(int i)来获取成员,代码省略  

    public void killVirus() {  
        System.out.println("****对文件夹'" + name + "'进行杀毒");  //模拟杀毒  

        //如果是Folder类型的成员,递归调用Folder的killVirus()方法  
        for(Object obj : folderList) {  
            ((Folder)obj).killVirus();  
        }  

        //如果是ImageFile类型的成员,调用ImageFile的killVirus()方法  
        for(Object obj : imageList) {  
            ((ImageFile)obj).killVirus();  
        }  

        //如果是TextFile类型的成员,调用TextFile的killVirus()方法  
        for(Object obj : textList) {  
            ((TextFile)obj).killVirus();  
        }  
    }   
}  

class Client {  
    public static void main(String args[]) {  
        Folder folder1,folder2,folder3;  
        folder1 = new Folder("Sunny的资料");  
        folder2 = new Folder("图像文件");  
        folder3 = new Folder("文本文件");  

        ImageFile image1,image2;  
        image1 = new ImageFile("小龙女.jpg");  
        image2 = new ImageFile("张无忌.gif");  

        TextFile text1,text2;  
        text1 = new TextFile("九阴真经.txt");  
        text2 = new TextFile("葵花宝典.doc");  

        folder2.addImageFile(image1);  
        folder2.addImageFile(image2);  
        folder3.addTextFile(text1);  
        folder3.addTextFile(text2);  
        folder1.addFolder(folder2);  
        folder1.addFolder(folder3);  

        folder1.killVirus();  
    }  
}  

日常来讲难点:
(1)
文件夹类Folder的陈设性和促里昂极其复杂,须要定义多个聚众存款和储蓄不一样类别的积极分子,而且亟需针对分化的分子提供增添、删除和收获等管理和访问成员的主意,存在大气的冗余代码,系统珍惜相比困难;
(2)
由于系统并未有提供抽象层,客商端代码必需有分别地对待当做容器的文书夹Folder和担当叶子的ImageFile和TextFile,不只怕统一对它们举办拍卖;
(3)
系统的油滑和可扩张性差,即使必要追加新的档案的次序的叶子和容器都供给对原有代码实行改造,举例假如需求在系统中追加一种新类型的摄像文件VideoFile,则必须修改Folder类的源代码,不然不能够在文件夹中加多录制文件。
设计方案:

4858.com 6

import java.util.*;  

//抽象文件类:抽象构件  
abstract class AbstractFile {  
    public abstract void add(AbstractFile file);  
    public abstract void remove(AbstractFile file);  
    public abstract AbstractFile getChild(int i);  
    public abstract void killVirus();  
}  

//图像文件类:叶子构件  
class ImageFile extends AbstractFile {  
    private String name;  

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

    public void add(AbstractFile file) {  
       System.out.println("对不起,不支持该方法!");  
    }  

    public void remove(AbstractFile file) {  
        System.out.println("对不起,不支持该方法!");  
    }  

    public AbstractFile getChild(int i) {  
        System.out.println("对不起,不支持该方法!");  
        return null;  
    }  

    public void killVirus() {  
        //模拟杀毒  
        System.out.println("----对图像文件'" + name + "'进行杀毒");  
    }  
}  

//文本文件类:叶子构件  
class TextFile extends AbstractFile {  
    private String name;  

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

    public void add(AbstractFile file) {  
       System.out.println("对不起,不支持该方法!");  
    }  

    public void remove(AbstractFile file) {  
        System.out.println("对不起,不支持该方法!");  
    }  

    public AbstractFile getChild(int i) {  
        System.out.println("对不起,不支持该方法!");  
        return null;  
    }  

    public void killVirus() {  
        //模拟杀毒  
        System.out.println("----对文本文件'" + name + "'进行杀毒");  
    }  
}  

//视频文件类:叶子构件  
class VideoFile extends AbstractFile {  
    private String name;  

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

    public void add(AbstractFile file) {  
       System.out.println("对不起,不支持该方法!");  
    }  

    public void remove(AbstractFile file) {  
        System.out.println("对不起,不支持该方法!");  
    }  

    public AbstractFile getChild(int i) {  
        System.out.println("对不起,不支持该方法!");  
        return null;  
    }  

    public void killVirus() {  
        //模拟杀毒  
        System.out.println("----对视频文件'" + name + "'进行杀毒");  
    }  
}  

//文件夹类:容器构件  
class Folder extends AbstractFile {  
    //定义集合fileList,用于存储AbstractFile类型的成员  
    private ArrayList<AbstractFile> fileList=new ArrayList<AbstractFile>();  
    private String name;  

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

    public void add(AbstractFile file) {  
       fileList.add(file);    
    }  

    public void remove(AbstractFile file) {  
        fileList.remove(file);  
    }  

    public AbstractFile getChild(int i) {  
        return (AbstractFile)fileList.get(i);  
    }  

    public void killVirus() {  
        System.out.println("****对文件夹'" + name + "'进行杀毒");  //模拟杀毒  

        //递归调用成员构件的killVirus()方法  
        for(Object obj : fileList) {  
            ((AbstractFile)obj).killVirus();  
        }  
    }  
}  

class Client {  
    public static void main(String args[]) {  
        //针对抽象构件编程  
        AbstractFile file1,file2,file3,file4,file5,folder1,folder2,folder3,folder4;  

        folder1 = new Folder("Sunny的资料");  
        folder2 = new Folder("图像文件");  
        folder3 = new Folder("文本文件");  
        folder4 = new Folder("视频文件");  

        file1 = new ImageFile("小龙女.jpg");  
        file2 = new ImageFile("张无忌.gif");  
        file3 = new TextFile("九阴真经.txt");  
        file4 = new TextFile("葵花宝典.doc");  
        file5 = new VideoFile("笑傲江湖.rmvb");  

        folder2.add(file1);  
        folder2.add(file2);  
        folder3.add(file3);  
        folder3.add(file4);  
        folder4.add(file5);  
        folder1.add(folder2);  
        folder1.add(folder3);  
        folder1.add(folder4);  

        //从“Sunny的资料”节点开始进行杀毒操作  
        folder1.killVirus();  
    }  
}  

树形结构的拍卖——组合形式(二)

11.2 组合情势概述

对此树形结构,当容器对象(如文件夹)的某一个措施被调用时,将遍历整个树形结构,搜索也含有这几个措施的成员对象(能够是容器对象,也得以是卡牌对象)并调用施行,牵一而动百,当中使用了递归调用的编写制定来对任何结构举办拍卖。由于容器对象和叶子对象在遵守上的分别,在动用那几个指标的代码中必得有分别地对待容器对象和叶子对象,而其实非常多动静下大家盼望一致地拍卖它们,因为对于这个指标的差别对待将会使得程序特别复杂。组合形式为缓和此类主题材料而诞生,它能够让叶子对象和容器对象的利用具备一致性。

组合格局定义如下:

构成情势(Composite
Pattern):组合三个对象变成树形结构以表示全部“全体—部分”关系的档次结构。组合格局对单个对象(即叶子对象)和组合对象(即容器对象)的应用全部一致性,组合形式又能够称为“全体—部分”(Part-Whole)格局,它是一种对象结构型情势。

在组合方式中引进了抽象构件类Component,它是兼具容器类和叶子类的国有父类,客商端针对Component进行编制程序。组合方式结构如图11-3所示:

4858.com 7

图11-3 组合情势结构图

在结合情势结构图中包含如下多少个剧中人物:

  • Component(抽象构件):它能够是接口或抽象类,为叶子构件和容器构件对象注明接口,在该剧中人物中得以富含全体子类共有行为的宣示和兑现。在空设想件中定义了拜谒及管制它的子构件的点子,如扩充子构件、删除子构件、获取子构件等。

  • Leaf(叶子构件):它在整合结构中意味着叶子节点目的,叶子节点未有子节点,它达成了在虚幻构件中定义的一坐一起。对于那一个访谈及管理子构件的艺术,能够经过丰裕等方法张开始拍戏卖。

  • Composite(容器构件):它在结合结构中表示容器节点目的,容器节点满含子节点,其子节点能够是卡牌节点,也得以是容器节点,它提供贰个集中用于存款和储蓄子节点,完成了在空虚拟件中定义的行事,包蕴那多少个访问及管理子构件的议程,在其职业方法中能够递归调用其子节点的工作方法。

结缘形式的关键是概念了贰个华而不实构件类,它不仅可以够象征叶子,又有何不可代表容器,而顾客端针对该抽象构件类进行编制程序,无须知道它到底意味着的是卡牌依旧容器,能够对其打开统一管理。同一时间容器对象与虚无构件类之间还创建多少个集聚关联关系,在容器对象中既可以够包含叶子,也得以分宽容器,以此实现递归组合,形成叁个树形结构。

设若不应用组合方式,客商端代码将大多地依赖于器皿对象复杂的在那之中贯彻结构,容器对象内部贯彻结构的退换将引起顾客代码的一再更动,带来了代码维护复杂、可扩张性差等弊病。组合情势的引进就要任其自然程度上缓和那么些主题素材。

下边通过轻巧的示范代码来深入分析组合方式的一一剧中人物的用处和完成。对于构成情势中的抽象构件剧中人物,其特出代码如下所示:

abstract class Component {  
    public abstract void add(Component c); //增加成员  
    public abstract void remove(Component c); //删除成员  
    public abstract Component getChild(int i); //获取成员  
    public abstract void operation();  //业务方法  
}

相似将抽象构件类设计为接口或抽象类,将具有子类共有方法的评释和落到实处放在抽象构件类中。对于顾客端来说,将对准抽象构件编制程序,而无须关注其具体子类是容器构件照旧叶子构件。

一旦持续抽象构件的是卡片构件,则其超级代码如下所示:

class Leaf extends Component {  
    public void add(Component c) {   
        //异常处理或错误提示   
    }     

    public void remove(Component c) {   
        //异常处理或错误提示   
    }  

    public Component getChild(int i) {   
        //异常处理或错误提示  
        return null;   
    }  

    public void operation() {  
        //叶子构件具体业务方法的实现  
    }   
}

作为抽象构件类的子类,在叶子构件中必要贯彻在抽象构件类中扬言的具有办法,包罗业务方法以及管理和访谈子构件的不二等秘书籍,但是叶子构件无法再包涵子构件,因而在叶子构件中完成子构件管理和拜谒方法时索要提供充裕处理或错误指示。当然,那毫无疑问会给叶子构件的贯彻带来麻烦。

例如一而再抽象构件的是容器构件,则其优秀代码如下所示:

class Composite extends Component {  
    private ArrayList<Component> list = new ArrayList<Component>();  

    public void add(Component c) {  
        list.add(c);  
    }  

    public void remove(Component c) {  
        list.remove(c);  
    }  

    public Component getChild(int i) {  
        return (Component)list.get(i);  
    }  

    public void operation() {  
        //容器构件具体业务方法的实现  
        //递归调用成员构件的业务方法  
        for(Object obj:list) {  
            ((Component)obj).operation();  
        }  
    }     
}

在容器构件中贯彻了在架空构件中声称的有所办法,既包含职业方法,也包罗用于访谈和治本成员子构件的不二秘诀,如add()、remove()和getChild()等办法。须要当心的是在促成具体业务方法时,由于容器构件充作的是容器剧中人物,包括成员构件,由此它将调用其成员构件的职业方法。在组成方式组织中,由于容器构件中仍然能够分包容器构件,由此在对容器构件进行拍卖时索要利用递归算法,即在容器构件的operation()方法中递归调用其成员构件的operation()方法。

思考

在重组格局结构图中,假设聚合关联关系不是从Composite到Component的,而是从Composite到Leaf的,如图11-4所示,会时有发生哪些的结果?

4858.com 8

图11-4 组合情势思量题结构图

  • Component:它能够是接口或抽象类,为叶子构件和容器构件对象声明接口,在该剧中人物中得以满含全部子类共有行为的宣示和落实。在空设想件中定义了寻访及管制它的子构件的秘籍,如增添子构件、删除子构件、获取子构件等。
  • Leaf:它在重组结构中意味叶子节点目的,叶子节点没有子节点,它落成了在空设想件中定义的一颦一笑。对于那多少个访谈及管理子构件的不二诀窍,能够透过特别等办法开展管理。
  • Composite:它在组合结构中象征容器节点指标,容器节点包括子节点,其子节点能够是卡牌节点,也能够是容器节点,它提供一个集中用于存储子节点,完成了在抽象构件中定义的行为,包罗那多少个访谈及管理子构件的措施,在其工作方法中得以递归调用其子节点的事情方法。

参与者

  • Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象证明接口,在该剧中人物中得以蕴涵全数子类共有行为的宣示和贯彻。在空设想件中定义了拜见及保管它的子构件的主意,如扩展子构件、删除子构件、获取子构件等。
  • Leaf(叶子构件):它在重组结构中意味叶子节点指标,叶子节点未有子节点,它完结了在虚幻构件中定义的一坐一起。对于那个访谈及处理子构件的不二等秘书籍,能够经过充裕等办法张开始拍戏卖。
  • Composite(容器构件):它在组合结构中象征容器节点目的,容器节点蕴涵子节点,其子节点能够是卡牌节点,也得以是容器节点,它提供一个凑合用于存款和储蓄子节点,完成了在空设想件中定义的行事,满含那三个访问及管理子构件的措施,在其工作方法中能够递归调用其子节点的事务方法。

二种情势

  • 晶莹剔透组合情势
      透明组合格局中,抽象构件Component中声称了具有用于管理成员对象的措施,富含add()、remove()以及getChild()等格局,那样做的补益是确定保证全数的预制构件类都有平等的接口。在客商端看来,叶子对象与容器对象所提供的点子是同一的,客商端能够等效地对待全数的指标。

    4858.com 9

**缺点:**不够安全,因为叶子对象和容器对象在本质上是有区别的。叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供add()、remove()以及getChild()等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)
  • 康宁构成情势【使用功用较高】
      安全构成情势中,在抽象构件Component中尚无注解任何用于管理成员对象的形式,而是在Composite类中扬言并贯彻那一个办法。

    4858.com 10

**缺点:**不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。

树形结构的管理——组合形式(三)

11.3 完整施工方案

为了让系统具有更加好的油滑和可扩充性,顾客端可以同样地对待文件和文书夹,Sunny公司开采人士使用组合方式来拓宽杀毒软件的框架设计,其主导组织如图11-5所示:

4858.com 11

图11-5 杀毒软件框架设计结构图

在图11-5中,
AbstractFile充任抽象构件类,Folder当作容器构件类,ImageFile、TextFile和VideoFile充任叶子构件类。完整代码如下所示:

import java.util.*;  

//抽象文件类:抽象构件  
abstract class AbstractFile {  
    public abstract void add(AbstractFile file);  
    public abstract void remove(AbstractFile file);  
    public abstract AbstractFile getChild(int i);  
    public abstract void killVirus();  
}  

//图像文件类:叶子构件  
class ImageFile extends AbstractFile {  
    private String name;  

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

    public void add(AbstractFile file) {  
       System.out.println("对不起,不支持该方法!");  
    }  

    public void remove(AbstractFile file) {  
        System.out.println("对不起,不支持该方法!");  
    }  

    public AbstractFile getChild(int i) {  
        System.out.println("对不起,不支持该方法!");  
        return null;  
    }  

    public void killVirus() {  
        //模拟杀毒  
        System.out.println("----对图像文件'" + name + "'进行杀毒");  
    }  
}  

//文本文件类:叶子构件  
class TextFile extends AbstractFile {  
    private String name;  

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

    public void add(AbstractFile file) {  
       System.out.println("对不起,不支持该方法!");  
    }  

    public void remove(AbstractFile file) {  
        System.out.println("对不起,不支持该方法!");  
    }  

    public AbstractFile getChild(int i) {  
        System.out.println("对不起,不支持该方法!");  
        return null;  
    }  

    public void killVirus() {  
        //模拟杀毒  
        System.out.println("----对文本文件'" + name + "'进行杀毒");  
    }  
}  

//视频文件类:叶子构件  
class VideoFile extends AbstractFile {  
    private String name;  

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

    public void add(AbstractFile file) {  
       System.out.println("对不起,不支持该方法!");  
    }  

    public void remove(AbstractFile file) {  
        System.out.println("对不起,不支持该方法!");  
    }  

    public AbstractFile getChild(int i) {  
        System.out.println("对不起,不支持该方法!");  
        return null;  
    }  

    public void killVirus() {  
        //模拟杀毒  
        System.out.println("----对视频文件'" + name + "'进行杀毒");  
    }  
}  

//文件夹类:容器构件  
class Folder extends AbstractFile {  
    //定义集合fileList,用于存储AbstractFile类型的成员  
    private ArrayList<AbstractFile> fileList=new ArrayList<AbstractFile>();  
    private String name;  

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

    public void add(AbstractFile file) {  
       fileList.add(file);    
    }  

    public void remove(AbstractFile file) {  
        fileList.remove(file);  
    }  

    public AbstractFile getChild(int i) {  
        return (AbstractFile)fileList.get(i);  
    }  

    public void killVirus() {  
        System.out.println("****对文件夹'" + name + "'进行杀毒");  //模拟杀毒  

        //递归调用成员构件的killVirus()方法  
        for(Object obj : fileList) {  
            ((AbstractFile)obj).killVirus();  
        }  
    }  
}

编辑如下客商端测验代码:

class Client {  
    public static void main(String args[]) {  
        //针对抽象构件编程  
        AbstractFile file1,file2,file3,file4,file5,folder1,folder2,folder3,folder4;  

        folder1 = new Folder("Sunny的资料");  
        folder2 = new Folder("图像文件");  
        folder3 = new Folder("文本文件");  
        folder4 = new Folder("视频文件");  

        file1 = new ImageFile("小龙女.jpg");  
        file2 = new ImageFile("张无忌.gif");  
        file3 = new TextFile("九阴真经.txt");  
        file4 = new TextFile("葵花宝典.doc");  
        file5 = new VideoFile("笑傲江湖.rmvb");  

        folder2.add(file1);  
        folder2.add(file2);  
        folder3.add(file3);  
        folder3.add(file4);  
        folder4.add(file5);  
        folder1.add(folder2);  
        folder1.add(folder3);  
        folder1.add(folder4);  

        //从“Sunny的资料”节点开始进行杀毒操作  
        folder1.killVirus();  
    }  
}

编译并运转程序,输出结果如下:

****对文件夹'Sunny的资料'进行杀毒
****对文件夹'图像文件'进行杀毒
----对图像文件'小龙女.jpg'进行杀毒
----对图像文件'张无忌.gif'进行杀毒
****对文件夹'文本文件'进行杀毒
----对文本文件'九阴真经.txt'进行杀毒
----对文本文件'葵花宝典.doc'进行杀毒
****对文件夹'视频文件'进行杀毒
----对视频文件'笑傲江湖.rmvb'进行杀毒

是因为在本实例中使用了整合情势,在空虚拟件类中扬言了具备办法,包含用于处理和访谈子构件的方式,如add()方法和remove()方法等,由此在ImageFile等叶子构件类中达成这个方法时必得开展对应的分外管理或错误提醒。在容器构件类Folder的killVirus()方法准将递归调用其成员对象的killVirus()方法,进而达成对全部树形结构的遍历。

若是急需转移操作节点,例如只需对文本夹“文本文件”举行杀毒,客商端代码只需修改一行就能够,将代码:

folder1.killVirus();

改为:

folder3.killVirus();

出口结果如下:

****对文件夹'文本文件'进行杀毒
----对文本文件'九阴真经.txt'进行杀毒
----对文本文件'葵花宝典.doc'进行杀毒

在切切实实贯彻时,大家得以创制图形化分界面让客户挑选所需操作的根节点,无须修改源代码,符合“开闭原则”,顾客端无须关注节点的档案的次序结构,能够对所选节点进行联合管理,提升系统的狡猾。

Component

用法

总结

主要优点:
(1)
组合情势能够驾驭地定义分档期的顺序的复杂对象,表示对象的满贯或局地档案的次序,它让顾客端忽略了档次的差距,方便对总体档期的顺序结构实行支配。
(2)
顾客端能够一样地行使多少个重组结构或内部单个对象,不必关怀管理的是单个对象照旧整个组合结构,简化了客商端代码。
(3)
在组合形式中加进新的器皿构件和叶子构件都很有益,无须对现成类库实行任何修改,适合“开闭原则”。
(4)
组合方式为树形结构的面向对象落成提供了一种灵活的应用方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的决定并非常轻易。

重中之重劣势:
  在追加新构件时很难对容器中的构件类型举办界定。有的时候候大家希望八个器皿中只好有少数特定项指标靶子,比如在某些文件夹中不得不分包文本文件,使用组合方式时,无法信任类型系统来施加这几个约束,因为它们都出自于一致的抽象层,在这种情景下,必得透过在运作时进行项目检查来贯彻,那几个实现进程较为复杂。

树形结构的管理——组合格局(四)

11.4 透明组合格局与安全构成方式

透过引进组合格局,Sunny公司统一希图的杀毒软件具备能够的可扩大性,在大增新的文件类型时,无须修改现成类库代码,只需追加贰个新的公文类作为AbstractFile类的子类就能够,不过出于在AbstractFile中扬言了大气用来管理和做客成员构件的诀窍,举个例子add()、remove()等措施,大家只可以在疯长的文本类中完毕那一个艺术,提供相应的一无所长提醒和十分管理。为了简化代码,大家有以下两个缓慢解决方案:

建设方案一:将卡牌构件的add()、remove()等办法的达成代码移至AbstractFile类中,由AbstractFile提供统一的暗许达成,代码如下所示:

//提供默认实现的抽象构件类  
abstract class AbstractFile {  
    public void add(AbstractFile file) {  
        System.out.println("对不起,不支持该方法!");  
    }  

    public void remove(AbstractFile file) {  
        System.out.println("对不起,不支持该方法!");  
    }  

    public AbstractFile getChild(int i) {  
        System.out.println("对不起,不支持该方法!");  
        return null;  
    }  

    public abstract void killVirus();  
}

要是客户端代码针对抽象类AbstractFile编程,在调用文件对象的那个格局时将现出谬误提醒。假若不希望出现任何不当提示,我们能够在顾客端定义文件对象时不应用抽象层,而直白选拔具体叶子构件自己,顾客端代码片段如下所示:

class Client {  
    public static void main(String args[]) {  
        //不能透明处理叶子构件  
        ImageFile file1,file2;  
        TextFile file3,file4;  
        VideoFile file5;  
        AbstractFile folder1,folder2,folder3,folder4;  
        //其他代码省略  
      }  
}

这般就生出了一种不透明的施用办法,即在顾客端无法整个针对性抽象构件类编制程序,须要运用具体叶子构件类型来定义叶子对象。

缓慢解决方案二:除了那个之外,还应该有一种缓慢解决办法是在空虚构件AbstractFile中不注明任何用于采访和治本成员构件的主意,代码如下所示:

abstract class AbstractFile {  
    public abstract void killVirus();  
}

那时,由于在AbstractFile中尚无表明add()、remove()等做客和管理成员的情势,其叶子构件子类无须提供实现;並且无论是顾客端如何定义叶子构件对象都无能为力调用到这一个措施,不必要做别的不当和充裕管理,容器构件再遵照供给追加访谈和管制作而成员的艺术,但此时也设有二个标题:顾客端不得不动用容器类自己来声称容器构件对象,不然不能够访谈个中新添的add()、remove()等措施,假使客商端一致性地看待叶子和容器,将会产生容器构件的增产对顾客端不可知,顾客端代码对于容器构件不或者再选拔抽象构件来定义,客商端代码片段如下所示:

class Client {  
    public static void main(String args[]) {  

        AbstractFile file1,file2,file3,file4,file5;  
        Folder folder1,folder2,folder3,folder4; //不能透明处理容器构件  
        //其他代码省略  
    }  
}

在运用组合格局时,根据抽象构件类的定义情势,大家可将整合形式分为透明组合格局和嘉峪关整合形式二种情势:

(1) 透明组合情势

透明组合方式中,抽象构件Component中宣示了独具用于管理成员对象的诀要,满含add()、remove()以及getChild()等办法,那样做的补益是保障全部的构件类都有同样的接口。在客商端看来,叶子对象与容器对象所提供的不二等秘书技是同样的,客商端能够长久以来地对待全数的对象。透明组合方式也是结合情势的正统格局,即使上边的减轻方案一在客户端能够有不透明的达成情势,不过出于在抽象构件中富含add()、remove()等艺术,因而它照旧晶莹剔透组合形式,透明组合情势的完好结构如图11-6所示:

4858.com 12

图11-6 透明组合方式结构图

透明组合格局的破绽是远远不足安全,因为叶子对象和容器对象在本质上是有分其余。叶子对象相当小概有下贰个档案的次序的目的,即不容许包涵成员对象,由此为其提供add()、remove()以及getChild()等措施是未有意义的,那在编写翻译阶段不会出错,但在运作阶段假使调用那几个主意可能会出错(若无提供对应的错误管理代码)。

(2) 安全构成形式

康宁构成模式中,在空洞构件Component中并没有注脚任何用于处理成员对象的点子,而是在Composite类中扬言并促成那么些主意。这种做法是安枕无忧的,因为一贯不向叶子对象提供那么些处理成员对象的诀要,对于叶子对象,顾客端不恐怕调用到那么些措施,那正是施工方案二所采用的兑现格局。安全整合方式的结构如图11-7所示:

4858.com 13

图11-7 安全整合格局结构图

平安构成格局的弱项是远远不足透明,因为叶子构件和容器构件具备分歧的形式,且容器构件中那一个用来管理成员对象的办法未有在空设想件类中定义,因而客商端无法一心针对抽象编制程序,必须有分别地看待叶子构件和容器构件。在实质上选取中,安全构成格局的应用效能也极高,在Java
AWT中利用的组合形式就是安枕而卧构成形式。

public abstract class Component { public abstract void add(Component component); public abstract void remove(Component component);}
代码助记
  • 容器构件关联两个华而不实构件List.
  • 在叶子构件中贯彻子构件管理和做客方法时必要提供特别管理或不当提醒。
  • 在重组形式组织中,由于容器构件中照旧能够分宽容器构件,因而在对容器构件进行管理时供给动用递归算法,即Composite的一举一动艺术中遍历调用List中有着行为举止格局。

适用场景

(1)
在具备整体和一部分的档案的次序结构中,希望因此一种艺术忽略全部与一些的反差,顾客端能够等效地对待它们。
(2) 在四个行使面向对象语言开垦的系统中须要管理一个树形结构。
(3)
在贰个系统中可见分离出叶子对象和容器对象,并且它们的类型不定点,要求追加一些新的花色。

树形结构的管理——组合方式(五)

11.5 公司集团结构

在读书和利用组合格局时,Sunny软件企业开采人士发掘树形结构其实随处可知,比如Sunny公司的公司结构正是“一棵规范的树”,如图11-8所示:

4858.com 14

图11-8 Sunny集团协会结构图

在Sunny软件商场的里边办公室系统SunnyOA系统中,有三个与商铺协会结构对应的树形菜单,行政职员能够给各级单位下发通报,那几个单位能够是总店的叁个机构,也得以是三个子公司,还是可以是分局的二个部门。客户只需求接纳一个根节点就能够兑现文告的下发操作,而无须关怀具体的兑现细节。那不正是结合情势的“特长”吗?于是Sunny集团开荒人士绘制了如图11-9所示结构图:

4858.com 15

图11-9 Sunny集团组织结构重组情势暗暗表示图

在图11-9中,“单位”当做了用空想来欺骗别人构件角色,“集团”充任了容器构件剧中人物,“研究开发部”、“财务部”和“人力财富部”当作了叶子构件剧中人物。

思考

怎么着编码完成图11-9中的“企业”类?

11.6 组合情势总计

整合格局应用面向对象的观念来贯彻树形结构的创设与拍卖,描述了怎么样将容器对象和叶子对象进行递归组合,完毕轻松,灵活性好。由于在软件开采中留存大气的树形结构,因而组合方式是一种选取功能较高的结构型设计方式,Java
SE中的AWT和Swing包的计划性就依照组合情势,在那一个分界面包中为顾客提供了汪洋的容器构件(如Container)和成员构件(如Checkbox、Button和TextComponent等),其协会如图11-10所示:
![图11-10 AWT组合模式结构暗中提示图

4858.com 16

java-awt-swing-composite.jpg

在图11-第10中学,Component类是虚幻构件,Checkbox、Button和TextComponent是卡牌构件,而Container是容器构件,在AWT中包括的卡片构件还可能有好些个,因为篇幅限制未有在图中各种列出。在一个容器构件中能够分包叶子构件,也足以持续富含容器构件,这一个叶子构件和容器构件一同构成了复杂的GUI分界面。

除此以外,在XML深入分析、协会结构树管理、文件系统设计等领域,组合情势都拿走了普及应用。

  1. 要害优点

结合情势的严重性优点如下:

(1)
组合情势能够知道地定义分档次的复杂对象,表示对象的总体或局部档次,它让客户端忽略了档次的差异,方便对全部档次结构进行支配。

(2)
顾客端能够一样地行使一个重组结构或内部单个对象,不必关怀处理的是单个对象依旧整个组合结构,简化了客户端代码。

(3)
在组合方式中加进新的器皿构件和叶子构件都很有益,无须对现成类库实行任何修改,切合“开闭原则”。

(4)
组合形式为树形结构的面向对象达成提供了一种灵活的缓慢解决方案,通过叶子对象和容器对象的递归组合,能够变成复杂的树形结构,但对树形结构的操纵却很简单。

  1. 首要瑕玷

整合形式的重要症结如下:

在追加新构件时很难对容器中的构件类型实行限制。有的时候候我们愿意贰个器皿中不得不有好几特定类型的对象,比如在有个别文件夹中只好分包文本文件,使用组合方式时,不能够借助类型系统来施加那么些约束,因为它们都来源于于同一的抽象层,在这种情形下,必需经过在运作时张开项目检查来贯彻,这些达成进度比较复杂。

  1. 适用场景

在偏下意况下能够虚拟选用组合格局:

(1)
在享有完整和部分的档次结构中,希望经过一种格局忽略全体与部分的差别,客商端能够一样地对待它们。

(2) 在二个运用面向对象语言开辟的种类中必要管理贰个树形结构。

(3)
在二个系统中能够分离出叶子对象和容器对象,何况它们的花色不稳定,要求充实部分新的档期的顺序。

练习

Sunny软件集团欲开荒二个界面控件库,分界面控件分为两大类,一类是单元控件,比方开关、文本框等,一类是容器控件,比如窗体、中间面板等,试用组合形式设计该界面控件库。

勤学苦练会在我的github上做掉

Leaf

两种形式

public class Leaf extends Component { @Override public void add(Component component) { // TODO Auto-generated method stub } @Override public void remove(Component component) { // TODO Auto-generated method stub }}
晶莹剔透组合格局

晶莹剔透组合形式中,泛泛构件Component中声称了具备用于管理成员对象的艺术,包罗add()、remove()以及getChild()等格局,那样做的益处是确定保证全体的部件类都有同样的接口。在客商端看来,叶子对象与容器对象所提供的方式是大同小异的,顾客端可以等效地对待全数的指标。透明组合方式也是构成方式的正规方式。

缺点是缺乏安全,因为叶子对象和容器对象在精神上是有分其他。叶子对象不大概有下三个档期的顺序的对象,即不恐怕带有成员对象,因此为其提供add()、remove()以及getChild()等措施是平昔不意义的

Composite

定西整合形式

安然整合情势中,在架空构件Component中尚无申明任何用于管理成员对象的不二秘技,而是在Composite类中宣示并落到实处那几个措施。

缺点是相当不足透明,因为叶子构件和容器构件具备不相同的办法,且容器构件中那多少个用来管理成员对象的主意未有在空虚拟件类中定义,因而顾客端不可能完全针对抽象编程,必需有分别地对待叶子构件和容器构件。

public class Composite extends Component { private List<Component> children = new ArrayList<Component>(); @Override public void add(Component component) { children.add(component); } @Override public void remove(Component component) { children.remove(component); }}

总结

结合情势的注重是概念了叁个架空构件类,它不仅可以够代表叶子,又能够表示容器,而客商端针对该抽象构件类实行编制程序,无须知道它到底意味着的是卡牌依旧容器,可以对其张开联合管理。同有时间容器对象与虚无构件类之间还树立一个聚焦关联关系,在容器对象中不仅能够包括叶子,也足以饱含容器,以此达成递归组合,造成八个树形结构。假若不利用组合方式,顾客端代码将过多地重视于器皿对象复杂的当中贯彻结构,容器对象内部贯彻结构的转换将唤起客商代码的每每退换,带来了代码维护复杂、可扩大性差等破绽。组合形式的引进就要自然水准上缓慢解决那么些难题。

优点
  • 重组情势能够掌握地定义分档案的次序的目眩神摇对象,表示对象的整整或局地档案的次序,它让顾客端忽略了档次的差别,方便对任何档次结构举行支配。
  • 顾客端可以等效地采用八个组合结构或内部单个对象,不必关注管理的是单个对象照旧整个组合结构,简化了客商端代码。
  • 在重组方式中加进新的器皿构件和叶子构件都异常低价,无须对现存类库进行任何改换,切合“开闭原则”。
  • 构成情势为树形结构的面向对象实现提供了一种灵活的消除方案,通过叶子对象和容器对象的递归组合,能够形成复杂的树形结构,但对树形结构的调节却特别轻巧。
4858.com ,缺点

在扩大新构件时很难对容器中的构件类型举行限定。有的时候候我们期待三个容器中不得不有少数特定类型的目的,比方在有些文件夹中只可以分包文本文件,使用组合方式时,不能借助类型系统来施加这么些约束,因为它们都来源于于同一的抽象层,在这种景况下,必需透过在运营时实行项目检查来完结,这些达成进程比较复杂。

适用场景
  • 在全数完全和一部分的档案的次序结构中,希望由此一种办法忽略全体与局地的异样,顾客端可以等效地对待它们。
  • 在一个利用面向对象语言开垦的系统中供给管理一个树形结构。
  • 在几个系统中可见分离出叶子对象和容器对象,並且它们的类型不稳固,须要充实部分新的项目。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有