设计模式-组合模式在Java中的使用示例-杀毒软件针对文件和文件夹进行杀毒

news2024/10/6 20:38:59

场景

组合模式

组合模式(Composite Pattern):

组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。

组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,

组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。

在组合模式中引入了抽象构件类Component,它是所有容器类和叶子类的公共父类,客户端针对

Component进行编程。组合模式结构如图

包含角色:

 Component(抽象构件):

它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。

在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。

 Leaf(叶子构件):

它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。

对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。

Composite(容器构件):

它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,

它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,

在其业务方法中可以递归调用其子节点的业务方法。

组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,

无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,

在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。

如果不使用组合模式,客户端代码将过多地依赖于容器对象复杂的内部实现结构,容器对象内部实现结构的变化将引起客户

代码的频繁变化,带来了代码维护复杂、可扩展性差等弊端。组合模式的引入将在一定程度上解决这些问题。

组合模式-树形结构的处理

树形结构在软件中随处可见,例如操作系统中的目录结构、应用软件中的菜单、办公系统中的公司组

织结构等等,如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题,组合模式通

过一种巧妙的设计方案使得用户可以一致性地处理整个树形结构或者树形结构的一部分,也可以一致性地

处理树形结构中的叶子节点(不包含子节点的节点)和容器节点(包含子节点的节点)。

欲开发一个杀毒(AntiVirus)软件,该软件既可以对某个文件夹(Folder)杀毒,也可以对某个指定的文件(File)进行杀毒。

该杀毒软件还可以根据各类文件的特点,为不同类型的文件提供不同的杀毒方式,

例如图像文件(ImageFile)和文本文件(TextFile)的杀毒方式就有所差异。

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主

实现

不使用组合模式

如果不使用组合模式,可能会这样实现

1、新建图像文件类

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

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

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

2、新建文本文件类

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

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

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

3、新建文件夹类

//文件夹类
public class Folder {
    private String name;

    //用于存储Folder类型的成员
    private ArrayList<Folder> folderList = new ArrayList<Folder>();
    //用于存储ImageFile类型的成员
    private ArrayList<ImageFile> imageList = new ArrayList<ImageFile>();
    //用于存储TextFile类型的成员
    private ArrayList<TextFile> textList = new ArrayList<TextFile>();

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

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

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

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

    //此处省略三种类型的删除成员的方法、获取成员的方法

    public void killVirus(){

        System.out.println("对文件夹"+name+"进行杀毒");

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

4、客户端调用示例如下

    public static void main(String[] args) {

        Folder folder1,folder2,folder3;
        folder1 = new Folder("工作资料");
        folder2 = new Folder("图片文件");
        folder3 = new Folder("文本文件");

        ImageFile imageFile1,imageFile2;
        imageFile1 = new ImageFile("背景图.jpg");
        imageFile2 = new ImageFile("示例图.gif");

        TextFile textFile1,textFile2;
        textFile1 = new TextFile("接口.doc");
        textFile2 = new TextFile("示例.txt");

        folder2.addImageFile(imageFile1);
        folder2.addImageFile(imageFile2);

        folder3.addTextFile(textFile1);
        folder3.addTextFile(textFile2);

        folder1.addFolder(folder2);
        folder1.addFolder(folder3);

        folder1.killVirus();
    }
}

分析存在的问题

(1) 文件夹类Folder的设计和实现都非常复杂,需要定义多个集合存储不同类型的成员,而且需要针对不同的成员

提供增加、删除和获取等管理和访问成员的方法,存在大量的冗余代码,系统维护较为困难;

(2) 由于系统没有提供抽象层,客户端代码必须有区别地对待充当容器的文件夹Folder和充当叶子

的ImageFile和TextFile,无法统一对它们进行处理;

(3) 系统的灵活性和可扩展性差,如果需要增加新的类型的叶子和容器都需要对原有代码进行修改,

例如如果需要在系统中增加一种新类型的视频文件VideoFile,则必须修改Folder类的源代码,

否则无法在文件夹中添加视频文件。

使用组合模式改造

1、新建抽象文件类作为抽象构件

//抽象文件类:抽象构件
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();
}

2、新建图像文件类作为叶子构件

//图像文件类:叶子构件
public class ImageFile extends AbstractFile {

    private String name;

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

    @Override
    public void add(AbstractFile file) {
        System.out.println("不支持该方法");
    }

    @Override
    public void remove(AbstractFile file) {
        System.out.println("不支持该方法");
    }

    @Override
    public AbstractFile getChild(int i) {
        System.out.println("不支持该方法");
        return null;
    }

    @Override
    public void killVirus() {
        System.out.println("对图像文件"+name+"进行杀毒");
    }
}

3、新建文本文件类

public class TextFile extends AbstractFile{

    private String name;

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

    @Override
    public void add(AbstractFile file) {
        System.out.println("不支持该方法");
    }

    @Override
    public void remove(AbstractFile file) {
        System.out.println("不支持该方法");
    }

    @Override
    public AbstractFile getChild(int i) {
        System.out.println("不支持该方法");
        return null;
    }

    @Override
    public void killVirus() {
        System.out.println("对文本文件"+name+"进行杀毒");
    }
}

4、新建文件夹类

import java.util.ArrayList;

public class Folder extends AbstractFile{

    //用于存储AbstractFile类型的成员
    private ArrayList<AbstractFile> fileList = new ArrayList<AbstractFile>();
    private String name;

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

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

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

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

    @Override
    public void killVirus() {
        System.out.println("对文件夹"+name+"进行杀毒");
        for (Object obj : fileList) {
            ((AbstractFile)obj).killVirus();
        }
    }
}

5、客户端调用方式如下

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

        //针对抽象构件编程
        AbstractFile file1,file2,file3,file4,folder1,folder2,folder3;

        folder1 = new Folder("工作资料");
        folder2 = new Folder("图片文件");
        folder3 = new Folder("文本文件");


        file1 = new ImageFile("背景图.jpg");
        file2 = new ImageFile("示例图.gif");

        file3 = new TextFile("接口.doc");
        file4 = new TextFile("示例.txt");

        folder2.add(file1);
        folder2.add(file2);

        folder3.add(file3);
        folder3.add(file4);

        folder1.add(folder2);
        folder1.add(folder3);

        folder1.killVirus();

    }
}

6、总结

通过引入组合模式,杀毒软件具有良好的可扩展性,在增加新的文件类型时,无须修改现有类库代码,

只需增加一个新的文件类作为AbstractFile类的子类即可,但是由于在AbstractFile中声明了大量用于管理和访问成员构件的方法,

例如add()、remove()等方法,我们不得不在新增的文件类中实现这些方法,提供对应的错误提示和异常处理。

所以代码还可简化将叶子构件的add()、remove()等方法的实现代码移至AbstractFile类中,由AbstractFile提供统一的默认实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/767921.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不会接口测试?用Postman轻松入门 —— Postman实现get和post请求

测试行业现在越来越卷&#xff0c;不会点接口测试好像简历都已经拿不出手了&#xff0c;但很多小伙伴都会头疼&#xff1a;接口测试应该怎么入门&#xff1f;那么多的接口测试工具应该学哪个&#xff1f; 其实&#xff0c;接口测试工具&#xff0c;就像吃饭用的筷子&#xff0…

25.JavaWeb-接口文档Swagger

1.Swagger swagger是一款可以根据resutful风格生成的生成的接口开发文档&#xff0c;并且支持做测试的一款中间软件。 1.1 接口文档 接口文档是用于描述API的一份文档&#xff0c;它包含了API的详细信息&#xff0c;包括API的请求和响应参数、接口路径、请求方法、数据类型、返…

企企通入选《2023数字化采购发展报告》,持续赋能企业数字化采购

近日&#xff0c;国内知名产业数字化服务平台亿邦智库联合中国物流与采购联合会公共采购分会共同发布了《2023数字化采购发展报告》。 企企通一直以来积极推动企业采购供应链数字化升级和变革&#xff0c;不断通过技术、产品、服务的创新&#xff0c;引领国内采购供应链数字化的…

保持领先竞争对手,从普通变为非凡;为您的Android应用赋能数据结构和算法

数据结构和算法为Android开发提供了基础数据存储和处理的工具。开发者可以根据具体需求选择合适的数据结构和算法&#xff0c;以提高应用的性能、效率和用户体验。Android框架也提供了许多内置的数据结构和算法实现&#xff0c;如Bundle、ArrayAdapter等&#xff0c;以便开发者…

开发工具篇第二十六讲:使用IDEA进行本地调试和远程调试

开发工具篇第二十六讲&#xff1a;使用IDEA进行本地调试和远程调试 Debug用来追踪代码的运行流程&#xff0c;通常在程序运行过程中出现异常&#xff0c;启用Debug模式可以分析定位异常发生的位置&#xff0c;以及在运行过程中参数的变化&#xff1b;并且在实际的排错过程中&am…

【Visual Studio Code】---自定义键盘快捷键设置

概述 一个好的文章能够帮助开发者完成更便捷、更快速的开发。书山有路勤为径&#xff0c;学海无涯苦作舟。我是秋知叶i、期望每一个阅读了我的文章的开发者都能够有所成长。 一、进入键盘快捷键设置 1、进入键盘快捷键设置方法1 使用快捷键进入键盘快捷键设置先按 Ctrl K再…

k8s如何访问 pod 元数据

如何访问 pod 元数据 **我们在 pod 中运行容器的时候&#xff0c;是否也会有想要获取当前 pod 的环境信息呢&#xff1f;**咱们写的 yaml 清单写的很简单&#xff0c;实际上部署之后&#xff0c; k8s 会给我们补充在 yaml 清单中没有写的字段&#xff0c;那么我们的 pod 环境信…

【软件测试】Git 实战详解 - 分支详细,看这篇就够了.,..

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Git 是如何保存数…

【项目 进程3】2.6 exce函数族 2.7 进程退出、孤儿进程、僵尸进程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 2.6 exec函数族介绍&#xff08;execute 执行&#xff09;exec函数族 2.7 进程退出、孤儿进程、僵尸进程进程退出孤儿进程僵尸进程 2.6 exec函数族介绍&#xff08;…

线程系列3-关于 CompletableFuture

线程系列3-关于 CompletableFuture 1、从 Future 接口说起2、CompletableFuture 对 Future 的改进2.1、CompletionStage 接口类2.2、runAsync 和 supplyAsync 创建子任务2.3、 whenComplete 和 exceptionally 异步任务回调钩子2.4、调用 handle() 方法统一处理异常和结果2.5、异…

计讯物联智慧景区应用解决方案,开启交互式智慧旅游新篇章

方案背景 后疫情时代&#xff0c;旅游市场逐步回暖。随着游客的旅游需求趋向个性化、多元化&#xff0c;景区的数字化转型升级势在必行。在此背景下&#xff0c;计讯物联充分发挥5G、云计算、物联网、大数据等技术的应用价值&#xff0c;以技术创新推动业务创新&#xff0c;面…

基于springboot+webservice+mysql实现的物业报修管理系统

基于springbootWebservicemysql实现的物业报修管理系统 一、系统介绍二、功能展示1.添加报修单(业主)2.缴费(业主)3.确定修复(管理员) 三、其它系统四、获取源码 一、系统介绍 系统主要功能&#xff1a; 通过JaxWsDynamicClientFactory调用Webservice接口实现物业报修管理。 业…

Linux·从 URL 输入到页面展现到底发生什么?

打开浏览器从输入网址到网页呈现在大家面前&#xff0c;背后到底发生了什么&#xff1f;经历怎么样的一个过程&#xff1f;先给大家来张总体流程图&#xff0c;具体步骤请看下文分解&#xff01; 总体来说分为以下几个过程: DNS 解析:将域名解析成 IP 地址TCP 连接&#xff1a…

【VUE】拖动侧边栏以便自由调整左右两侧的宽度

效果 &#xff08;1&#xff09;拖动前 &#xff08;2&#xff09;拖动后 主要代码 <template><el-row class"contnet" :gutter"20">// 1. 左侧树<el-col id"left-tree" class"left-tree" :offset"0" :…

文心一言 VS 讯飞星火 VS chatgpt (62)-- 算法导论6.5 1题

文心一言 VS 讯飞星火 VS chatgpt &#xff08;62&#xff09;-- 算法导论6.5 1题 一、试说明 HEAP-EXTRACT-MAX在堆A(15&#xff0c;13&#xff0c;9&#xff0c;5&#xff0c;12&#xff0c;8&#xff0c;7&#xff0c;4&#xff0c;0&#xff0c;6&#xff0c;2&#xff0c…

高时空分辨率、高精度一体化预测技术之风、光、水能源自动化预测技术

能源是国民经济发展和人民生活必须的重要物质基础。在过去的200多年里&#xff0c;建立在煤炭、石油、天然气等化石燃料基础上的能源体系极大的推动了人类社会的发展。但是人类在使用化石燃料的同时&#xff0c;也带来了严重的环境污染和生态系统破坏。近年来&#xff0c;世界各…

Docker 仓库与注册表: 构建可靠的容器镜像生态系统

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

leetcode 445. Add Two Numbers II(两数相加)

用链表代表2个数字&#xff0c;这2个数字相加的和用链表返回。 最高位在链表的head. 思路&#xff1a; 1.链表逆序 数字相加是从低位到高位的&#xff0c;然而链表中的数字是从高位指向低位。 所以涉及到链表的逆序。 逆序之后只需从head到tail把两个链表的数字相加&#x…

BCG的Ribbonbar的categroy滚动控制处理方法

重点&#xff1a; 1.BCG的Ribbonbar可以通过鼠标滚轮进行界面滚动变化。 2.想要禁止这个功能&#xff0c;只能通过继承PreTranslateMessage消息&#xff0c;将滚动的消息进行屏蔽即可。它们没有控制滚动的函数处理 class CLbCBCGPRibbonBar : public CBCGPRibbonBar { public…

如何写一个Python三方包供别人使用

第一步&#xff0c;新建文件夹 好的&#xff0c;我们先new一个项目&#xff0c;空文件夹就行&#xff0c;例如新建一个叫my-wheel的项目 第二步&#xff0c;写核心代码 新建一个mywheel的包&#xff0c;包下新建文件example.py def msg():return "a python lib named …