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

11.3 完整解决方案

为了让系统具有更好的灵活性和可扩展性,客户端可以一致地对待文件和文件夹,Sunny公司开发人员使用组合模式来进行杀毒软件的框架设计,其基本结构如图11-5所示:

树形结构的处理——组合模式(三) - 图1

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

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

  1. import java.util.*;
  2. //抽象文件类:抽象构件
  3. abstract class AbstractFile {
  4. public abstract void add(AbstractFile file);
  5. public abstract void remove(AbstractFile file);
  6. public abstract AbstractFile getChild(int i);
  7. public abstract void killVirus();
  8. }
  9. //图像文件类:叶子构件
  10. class ImageFile extends AbstractFile {
  11. private String name;
  12. public ImageFile(String name) {
  13. this.name = name;
  14. }
  15. public void add(AbstractFile file) {
  16. System.out.println("对不起,不支持该方法!");
  17. }
  18. public void remove(AbstractFile file) {
  19. System.out.println("对不起,不支持该方法!");
  20. }
  21. public AbstractFile getChild(int i) {
  22. System.out.println("对不起,不支持该方法!");
  23. return null;
  24. }
  25. public void killVirus() {
  26. //模拟杀毒
  27. System.out.println("----对图像文件'" + name + "'进行杀毒");
  28. }
  29. }
  30. //文本文件类:叶子构件
  31. class TextFile extends AbstractFile {
  32. private String name;
  33. public TextFile(String name) {
  34. this.name = name;
  35. }
  36. public void add(AbstractFile file) {
  37. System.out.println("对不起,不支持该方法!");
  38. }
  39. public void remove(AbstractFile file) {
  40. System.out.println("对不起,不支持该方法!");
  41. }
  42. public AbstractFile getChild(int i) {
  43. System.out.println("对不起,不支持该方法!");
  44. return null;
  45. }
  46. public void killVirus() {
  47. //模拟杀毒
  48. System.out.println("----对文本文件'" + name + "'进行杀毒");
  49. }
  50. }
  51. //视频文件类:叶子构件
  52. class VideoFile extends AbstractFile {
  53. private String name;
  54. public VideoFile(String name) {
  55. this.name = name;
  56. }
  57. public void add(AbstractFile file) {
  58. System.out.println("对不起,不支持该方法!");
  59. }
  60. public void remove(AbstractFile file) {
  61. System.out.println("对不起,不支持该方法!");
  62. }
  63. public AbstractFile getChild(int i) {
  64. System.out.println("对不起,不支持该方法!");
  65. return null;
  66. }
  67. public void killVirus() {
  68. //模拟杀毒
  69. System.out.println("----对视频文件'" + name + "'进行杀毒");
  70. }
  71. }
  72. //文件夹类:容器构件
  73. class Folder extends AbstractFile {
  74. //定义集合fileList,用于存储AbstractFile类型的成员
  75. private ArrayList<AbstractFile> fileList=new ArrayList<AbstractFile>();
  76. private String name;
  77. public Folder(String name) {
  78. this.name = name;
  79. }
  80. public void add(AbstractFile file) {
  81. fileList.add(file);
  82. }
  83. public void remove(AbstractFile file) {
  84. fileList.remove(file);
  85. }
  86. public AbstractFile getChild(int i) {
  87. return (AbstractFile)fileList.get(i);
  88. }
  89. public void killVirus() {
  90. System.out.println("****对文件夹'" + name + "'进行杀毒"); //模拟杀毒
  91. //递归调用成员构件的killVirus()方法
  92. for(Object obj : fileList) {
  93. ((AbstractFile)obj).killVirus();
  94. }
  95. }
  96. }

编写如下客户端测试代码:

  1. class Client {
  2. public static void main(String args[]) {
  3. //针对抽象构件编程
  4. AbstractFile file1,file2,file3,file4,file5,folder1,folder2,folder3,folder4;
  5. folder1 = new Folder("Sunny的资料");
  6. folder2 = new Folder("图像文件");
  7. folder3 = new Folder("文本文件");
  8. folder4 = new Folder("视频文件");
  9. file1 = new ImageFile("小龙女.jpg");
  10. file2 = new ImageFile("张无忌.gif");
  11. file3 = new TextFile("九阴真经.txt");
  12. file4 = new TextFile("葵花宝典.doc");
  13. file5 = new VideoFile("笑傲江湖.rmvb");
  14. folder2.add(file1);
  15. folder2.add(file2);
  16. folder3.add(file3);
  17. folder3.add(file4);
  18. folder4.add(file5);
  19. folder1.add(folder2);
  20. folder1.add(folder3);
  21. folder1.add(folder4);
  22. //从“Sunny的资料”节点开始进行杀毒操作
  23. folder1.killVirus();
  24. }
  25. }

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

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

由于在本实例中使用了组合模式,在抽象构件类中声明了所有方法,包括用于管理和访问子构件的方法,如add()方法和remove()方法等,因此在ImageFile等叶子构件类中实现这些方法时必须进行相应的异常处理或错误提示。在容器构件类Folder的killVirus()方法中将递归调用其成员对象的killVirus()方法,从而实现对整个树形结构的遍历。

如果需要更换操作节点,例如只需对文件夹“文本文件”进行杀毒,客户端代码只需修改一行即可,将

代码:

  1. folder1.killVirus();

改为:

  1. folder3.killVirus();

输出结果如下:

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

在具体实现时,我们可以创建图形化界面让用户选择所需操作的根节点,无须修改源代码,符合“开闭原则”,客户端无须关心节点的层次结构,可以对所选节点进行统一处理,提高系统的灵活性。