首页 > 编程语言 >设计模式-组合模式在Java中的使用示例-杀毒软件针对文件和文件夹进行杀毒

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

时间:2023-07-18 11:25:38浏览次数:62  
标签:Java name 示例 void AbstractFile 构件 Folder 设计模式 public

场景

组合模式

组合模式(Composite Pattern):

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

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

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

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

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

 

包含角色:

 Component(抽象构件):

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

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

 Leaf(叶子构件):

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

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

Composite(容器构件):

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi

实现

不使用组合模式

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

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提供统一的默认实现。

标签:Java,name,示例,void,AbstractFile,构件,Folder,设计模式,public
From: https://www.cnblogs.com/badaoliumangqizhi/p/17562359.html

相关文章

  • python 使用OpenCV进行目标检测和识别的完整示例
    #导入OpenCV库importcv2#加载图像image=cv2.imread('image.jpg')#创建Haar级联分类器cascade_classifier=cv2.CascadeClassifier('haarcascade_frontalface_default.xml')#检测目标图像中的行人gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)faces=ca......
  • javascript-js正则表达式-常用的正则表达式
    js常用的正则表达式1.匹配Email地址:constemailRegex=/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;2.匹配URL:consturlRegex=/^(https?:\/\/)?([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(:[0-9]+)?(\/[^\s]*)?$/;3.匹配日期(YYYY-MM-DD):constdateRegex=/^\d{4}-(0[1-9]|......
  • 介绍社交论坛问答发帖系统源码-java+vue+uniapp开发前后端
    前后端分离社交论坛问答发帖BBS源码,社交论坛小程序|H5论坛|,app论坛是java+vue+uniapp开发的前后端分离社交论坛问答发帖/BBS项目,包括论坛图文帖,视频,圈子,IM私聊,微信支付,付费贴,积分签到,钱包充值等论坛小程序论坛app完整功能演示地址:www.runruncode.com/java/19462.html ......
  • 使用 JavaScript 脚本来进行复杂的查询改写
    有这么一个需求:网关里怎样对跨集群搜索进行支持的呢?我想实现:输入的搜索请求是lp:9200/index1/_search这个索引在3个集群上,需要跨集群检索,也就是网关能否改成lp:9200/cluster01:index1,cluster02,index1,cluster03:index1/_search呢?索引有一百多个,名称不一定是app,还......
  • Java中的深克隆和浅克隆(Clone)
    浅克隆(shallowclone)和深克隆(deepclone)是两种不同的对象复制方法。浅克隆会创建一个新对象,然后将原始对象的所有字段复制到新对象中。如果字段是基本类型,则它们的值将被直接复制。如果字段是引用类型,则只会复制引用,而不会复制引用指向的对象。这意味着原始对象和克隆对象中的引......
  • Java中七七八八的各种锁
    乐观锁or悲观锁乐观锁即蹲坑不锁门,只会在更新的时候判断有没有其他线程去更改数据,有的话就回滚典型:悲观锁即进厕所立马锁门,其他线程来了即阻塞,进到阻塞队列中,等待主线程蹲坑完毕后,按顺序获取典型:synchronized和ReentrantLock独占锁or共享锁顾名思义,独占锁即获......
  • beginnersbook C 语言示例·翻译完成 | ApacheCN
    译者:飞龙协议:CCBY-NC-SA4.0简单的C程序C语言中的HelloWorld程序C程序:检查给定的整数是正还是负C程序:使用递归函数反转给定的数字C程序:查找最大的三个数字C程序:显示Fibonacci序列C程序:使用递归查找数字的阶乘C程序:查找给定范围内的素数C程序:检查阿姆斯特朗数C程序......
  • Java 变量类型
    在Java中,变量可以分为以下几种类型:变量(LocalVariables):定义在方法、构造方法或代码块内部的变量。局部变量在声明时被创建,并在方法执行完毕后被销毁。局部变量没有默认值,必须在使用前进行初始化。参数(Parameters):定义在方法或构造方法的参数列表中的变量。参数是用于接收方法......
  • Java爬虫--HttpClient-Post请求
    //下面是一个demo:packagetest;importorg.apache.http.HttpEntity;importorg.apache.http.client.methods.CloseableHttpResponse;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.impl.client.HttpClients;importorg.apache.http.util......
  • java ExecutorService 主线程不停吗
    如何实现"JavaExecutorService主线程不停"1.简介在Java中,可以使用ExecutorService来实现多线程任务的执行和管理。主线程指的是调用ExecutorService的线程,在任务执行完成之前,主线程通常是需要等待的,但有时候我们希望主线程不停止,而是继续执行其他操作。本文将介绍如何实现这......