zoukankan      html  css  js  c++  java
  • 组合模式小试

    组合模式是一种功能比较单一的设计模式,一般与其他设计模式搭配使用。本篇简单模拟了一下自动构建xml文件的小程序。

    转载请注明出处http://www.cnblogs.com/zrtqsk/p/3725154.html,谢谢!

    一、介绍

      还是先来看一下《研磨设计模式》的介绍——将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

      组合模式的本质——统一叶子对象和组合对象。

      什么是组合模式呢?说白了,就是用一个抽象类把对象的整体和部分的操作统一起来。在外部看来,整个对象无论是整体还是部分,操作都是一样的。最常见使用组合模式的譬如我们的数据结构——树。树有3种模块,分别是根、枝、叶。这3个都分别有各自的特征。我们就可以用组合模式构建一个抽象类,将3者一样的操作在抽象类中实现,不一样的操作构建成抽象方法留给子类实现。这样在外界看来,整棵树自成一体,无须区分哪个是根、哪个是枝、叶。

    二、我的实现

      在这里,我们利用组合模式来做一个自动构建xml文件的小程序,也算是简单模拟了一下dom4j的功能。

      xml文件分别有哪些部分组成?完整的xml文件,最顶端是xml声明,下面是xml的处理指令,然后下面是文档类型声明,然后下面是一个根元素,根元素包括了一个或多个子元素。而作为元素而言,又包括了元素内容、属性键值对等等。同时,xml注释可以在任意地方添加。

      通常简单的xml文件只包括了xml声明、根元素(包含各种内容)以及xml注释。

      由于xml声明只出现一次,可以在总的构建类中再处理。这里我们主要处理元素和xml注释。因为注释可以在任何地方添加,也可以抽象为元素的一种。

    1、组合模式最麻烦的,就是这个抽象类,下面是我的抽象类,包含了元素和xml注释所有可能的方法:

     1 package composite.qsk;
     2 
     3 import java.util.List;
     4 
     5 public abstract class AbstractElement {
     6 
     7     // 内容(包含在"<X>"和"</X>"之间的部分,没有用“<”和“>”括起来)
     8     protected String content = null;
     9 
    10     // 元素层,根层数为0,其子元素层数为1,依次
    11     private int level = 0;
    12 
    13     // 抽象方法、得到本元素所有内容(类似“<a c=d>efgh </a>”)
    14     public abstract String getAllContent();
    15 
    16     public List<XMLElement> getChildElements()
    17     {
    18         throw new UnsupportedOperationException("对象不支持此功能");
    19     }
    20 
    21     public int getLevel()
    22     {
    23         return level;
    24     }
    25 
    26     public void setLevel(int level)
    27     {
    28         this.level = level;
    29     }
    30 
    31     // 设置本元素内容
    32     public boolean setContent(String content)
    33     {
    34         boolean flag = false;
    35         if (content != null)
    36         {
    37             this.content = content;
    38             flag = true;
    39         }
    40         return flag;
    41     }
    42 
    43     // 得到本元素的内容
    44     public String getContent()
    45     {
    46         return content;
    47     }
    48 
    49     // 增加属性
    50     public boolean addAttribute(XMLAttribute xmlAttribute)
    51     {
    52         throw new UnsupportedOperationException("对象不支持此功能");
    53     }
    54 
    55     public boolean addAttribute(String aName, String aValue)
    56     {
    57         throw new UnsupportedOperationException("对象不支持此功能");
    58     }
    59 
    60     // 根据属性名移除属性
    61     public boolean removeAtrribute(String name)
    62     {
    63         throw new UnsupportedOperationException("对象不支持此功能");
    64     }
    65 
    66     // 增加子元素
    67     public boolean addElement(AbstractElement xmlElement)
    68     {
    69         throw new UnsupportedOperationException("对象不支持此功能");
    70     }
    71 
    72     // 根据索引移除子元素
    73     public AbstractElement removeElement(int index)
    74     {
    75         throw new UnsupportedOperationException("对象不支持此功能");
    76     }
    77 
    78     // 根据索引得到子元素
    79     public AbstractElement getElement(int index)
    80     {
    81         throw new UnsupportedOperationException("对象不支持此功能");
    82     }
    83 
    84     // 得到本元素元素名
    85     public String getName()
    86     {
    87         throw new UnsupportedOperationException("对象不支持此功能");
    88     }
    89 
    90     // 设置元素名
    91     public boolean setName(String elementName)
    92     {
    93         throw new UnsupportedOperationException("对象不支持此功能");
    94     }
    95 }

    如上,由于我们将注释定位为元素的一种,那么原本一些元素有的方法,注释都是不支持的,那么注释操作这些方法时,就会自动调用父类的方法,抛出异常UnsupportedOperationException("对象不支持此功能")

    2、接下来就是我们的元素类,继承了AbstractElement,当然要重写里面的很多方法,如下:

      1 package composite.qsk;
      2 
      3 import java.util.ArrayList;
      4 import java.util.List;
      5 
      6 public class XMLElement extends AbstractElement {
      7 
      8     // 元素名
      9     private String name = null;
     10     // 子元素列表
     11     protected List<AbstractElement> childElements = null;
     12     // 子属性列表
     13     protected List<XMLAttribute> attributes = null;
     14 
     15     public XMLElement(String name)
     16     {
     17         this.name = name;
     18     }
     19 
     20     // 增加子元素
     21     public boolean addElement(AbstractElement xmlElement)
     22     {
     23         boolean flag = false;
     24         if (childElements == null)
     25         {
     26             childElements = new ArrayList<AbstractElement>();
     27         }
     28         if (xmlElement != null)
     29         {
     30             xmlElement.setLevel(this.getLevel() + 1);
     31             childElements.add(xmlElement);
     32             flag = true;
     33         }
     34         return flag;
     35     }
     36 
     37     // 根据索引移除子元素
     38     public AbstractElement removeElement(int index)
     39     {
     40         if (childElements == null)
     41         {
     42             return null;
     43         }
     44         return childElements.remove(index);
     45     }
     46 
     47     // 根据索引得到子元素
     48     public AbstractElement getElement(int index)
     49     {
     50         if (childElements == null)
     51         {
     52             return null;
     53         }
     54         return childElements.get(index);
     55     }
     56 
     57     // 得到本元素元素名
     58     public String getName()
     59     {
     60         return name;
     61     }
     62 
     63     // 设置元素名
     64     public boolean setName(String elementName)
     65     {
     66         boolean flag = false;
     67         if (elementName != null)
     68         {
     69             this.name = elementName;
     70             flag = true;
     71         }
     72         return flag;
     73     }
     74 
     75     // 增加属性
     76     public boolean addAttribute(XMLAttribute attribute)
     77     {
     78         boolean flag = true;
     79         if (attributes == null)
     80         {
     81             attributes = new ArrayList<XMLAttribute>();
     82         }
     83         if (attribute != null)
     84         {
     85             flag = attributes.add(attribute);
     86         }
     87         return flag;
     88     }
     89 
     90     public boolean addAttribute(String name, String value)
     91     {
     92         return addAttribute(new XMLAttribute(name, value));
     93     }
     94 
     95     // 根据属性名移除属性
     96     public boolean removeAtrribute(String name)
     97     {
     98         boolean flag = false;
     99         if (attributes == null)
    100         {
    101             return false;
    102         }
    103         if (name != null)
    104         {
    105             for (XMLAttribute a : attributes)
    106             {
    107                 if (a.getAttributeName().equals(name))
    108                 {
    109                     attributes.remove(a);
    110                     flag = true;
    111                     return flag;
    112                 }
    113             }
    114         }
    115         return flag;
    116     }
    117 
    118     // 得到元素所有内容
    119     @Override
    120     public String getAllContent()
    121     {
    122         StringBuilder allContent = new StringBuilder();
    123         // 行首空白
    124         StringBuilder space = new StringBuilder();
    125         for (int i = 0; i < getLevel(); i++)
    126         {
    127             space.append("    ");
    128         }
    129         // 拼接元素名
    130         allContent.append(space).append("<" + name);
    131         // 拼接属性
    132         if (attributes != null && attributes.size() > 0)
    133         {
    134             for (XMLAttribute a : attributes)
    135             {
    136                 allContent.append(" " + a.getAttributeName() + ":" + a.getAttributeContent());
    137             }
    138         }
    139         allContent.append(">
    ");
    140         // 拼接元素内容
    141         if (content != null)
    142         {
    143             allContent.append(space).append(content).append("
    ");
    144         }
    145         // 拼接子元素
    146         if (childElements != null && childElements.size() > 0)
    147         {
    148             for (AbstractElement e : childElements)
    149             {
    150                 allContent.append(e.getAllContent());
    151             }
    152         }
    153         // 拼接元素名后缀
    154         allContent.append(space).append("</" + name + ">
    ");
    155         return allContent.toString();
    156     }
    157 }

    如上,AbstractElement类的所有抛异常的方法,这里都重写了。

    3、然后就是我们的注释元素类了,如下:

     1 package composite.qsk;
     2 
     3 public class AnnotationElement extends AbstractElement{
     4 
     5     public AnnotationElement(String content) {
     6         super.content = content;
     7     }
     8 
     9     @Override
    10     public String getAllContent()
    11     {
    12         StringBuilder allContent = new StringBuilder();
    13         //行首空白
    14         StringBuilder space = new StringBuilder();
    15         for(int i = 0;i<getLevel();i++) {
    16             space.append("    "); 
    17         }
    18         //拼接元素名
    19         allContent.append(space).append("<!--");
    20         //拼接元素内容
    21         if(content != null) {
    22             allContent.append(content);
    23         }
    24         //拼接元素名后缀
    25         allContent.append("-->
    ");
    26         return allContent.toString();
    27     }
    28 }

    这个类很简单。只是做了简单的拼接。

    4、此外,还有一个简单的属性类,代表元素的属性,如下:

     1 package composite.qsk;
     2 
     3 public class XMLAttribute {
     4 
     5     private String attributeName = null;
     6 
     7     private String attributeContent = null;
     8 
     9     public String getAttributeName()
    10     {
    11         return attributeName;
    12     }
    13 
    14     public void setAttributeName(String attributeName)
    15     {
    16         this.attributeName = attributeName;
    17     }
    18 
    19     public String getAttributeContent()
    20     {
    21         return attributeContent;
    22     }
    23 
    24     public void setAttributeContent(String attributeContent)
    25     {
    26         this.attributeContent = attributeContent;
    27     }
    28 
    29     public XMLAttribute(String attributeName, String attributeContent)
    30     {
    31         super();
    32         this.attributeName = attributeName;
    33         this.attributeContent = attributeContent;
    34     }
    35 
    36 }

    5、完成构建文件的功能需要一个总的类负责,也负责组装xml声明,如下:

     1 package composite.qsk;
     2 
     3 import java.io.BufferedWriter;
     4 import java.io.File;
     5 import java.io.FileOutputStream;
     6 import java.io.IOException;
     7 import java.io.OutputStreamWriter;
     8 
     9 public class XMLParser {
    10 
    11     // 文件名
    12     private String fileName = "";
    13     // 文件
    14     private File xmlFile = null;
    15     // XML声明
    16     private String xmlDeclaration = "<?xml version="1.0" encoding="UTF-8">";
    17     // 根元素
    18     private AbstractElement root = null;
    19     // 所有内容
    20     private String allContent;
    21 
    22     public XMLParser(String fileName)
    23     {
    24         if (fileName.endsWith(".xml"))
    25         {
    26             this.fileName = fileName;
    27         }
    28         else
    29         {
    30             this.fileName = fileName + ".xml";
    31         }
    32         xmlFile = new File(fileName);
    33     }
    34 
    35     public XMLParser()
    36     {
    37         this("newXmlFile.xml");
    38     }
    39 
    40     // 拼接所有内容
    41     public String getAllContent()
    42     {
    43         return allContent = xmlDeclaration + "
    " + root.getAllContent();
    44     }
    45 
    46     public String getXmlDeclaration()
    47     {
    48         return xmlDeclaration;
    49     }
    50 
    51     public void setXmlDeclaration(String xmlDeclaration)
    52     {
    53         this.xmlDeclaration = xmlDeclaration;
    54     }
    55 
    56     public AbstractElement getRoot()
    57     {
    58         return root;
    59     }
    60 
    61     public void setRoot(AbstractElement root)
    62     {
    63 
    64         if (root != null && root instanceof XMLElement)
    65         {
    66             this.root = root;
    67         }
    68         else
    69         {
    70             throw new UnsupportedOperationException("对象不支持此功能");
    71         }
    72     }
    73 
    74     public String getFileName()
    75     {
    76         return fileName;
    77     }
    78 
    79     public void setFileName(String fileName)
    80     {
    81         this.fileName = fileName;
    82     }
    83 
    84     // 输出文件
    85     public void createFile() throws IOException
    86     {
    87         BufferedWriter bos = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(xmlFile)));
    88         bos.write(getAllContent());
    89         if (bos != null)
    90             bos.close();
    91     }
    92 
    93 }

    6、下面是简单的测试了:

     1 package composite.qsk;
     2 
     3 import java.io.IOException;
     4 
     5 public class Test {
     6 
     7     public static void main(String[] args)
     8     {
     9         XMLParser xml = new XMLParser("myFile");
    10         //
    11         AbstractElement root = new XMLElement("qsk");
    12         // 设置根
    13         xml.setRoot(root);
    14         // 各个元素
    15         AbstractElement e1 = new XMLElement("e1");
    16         AbstractElement e2 = new XMLElement("e2");
    17         AbstractElement e3 = new XMLElement("e3");
    18         AbstractElement e4 = new XMLElement("e4");
    19         AbstractElement e5 = new XMLElement("e5");
    20         AbstractElement e6 = new XMLElement("e6");
    21         AbstractElement e7 = new AnnotationElement("这是一个注释");
    22         AbstractElement e8 = new AnnotationElement("这是一个注释");
    23         // 组合各个元素
    24         root.addElement(e8);
    25         root.addElement(e1);
    26         root.addElement(e2);
    27         e2.addElement(e7);
    28         e1.addElement(e3);
    29         e2.addElement(e4);
    30         e3.addElement(e5);
    31         e4.addElement(e6);
    32         // 设置内容
    33         e5.setContent("e5的内容啊");
    34         e2.setContent("bbbbbbbb");
    35         e6.setContent("e6的内容啊");
    36         // 设置属性
    37         root.addAttribute(new XMLAttribute("root的属性名", "root的属性值"));
    38         e1.addAttribute("e1的属性名", "e1的属性值");
    39         // 打印
    40         System.out.println(xml.getAllContent());
    41         // 输出xml文件
    42         try
    43         {
    44             xml.createFile();
    45         } catch (IOException e)
    46         {
    47             e.printStackTrace();
    48         }
    49     }
    50 }

    7、结果如下:

    <?xml version="1.0" encoding="UTF-8">
    <qsk root的属性名:root的属性值>
        <!--这是一个注释-->
        <e1 e1的属性名:e1的属性值>
            <e3>
                <e5>
                e5的内容啊
                </e5>
            </e3>
        </e1>
        <e2>
        bbbbbbbb
            <!--这是一个注释-->
            <e4>
                <e6>
                e6的内容啊
                </e6>
            </e4>
        </e2>
    </qsk>

    除了如上控制台的输出外,我们在工程目录也可以看到一个qsk.xml的文件。里面的内容与上相同。

    在这个示例中,我们可以看到,通过一个root元素来得到其全部内容是通过方法getAllContent()的递归,这是一种变形的递归。

    三、安全性和透明性

    在上面的例子中,我们很明显可以发现,在抽象类中将子类所有可能的方法列出是一件很繁琐的事,看起来也不够优雅。不过这样带来的好处是用户根本不用区分使用的AbstractElement到底是元素还是注释。直接使用就可以了。这就叫做为了透明性而牺牲了安全性,使用注释调用不属于注释的方法,就会报异常。

    同样的,我们可以将抽象类完全的抽象,只放子类共有的方法,这样会带来的好处是不会出上述的异常,变的安全,不过子类不再透明。使用时,需要区分到底是哪个类型。各种操作也不再方便。

    如下所示:

    1、将抽象类AbstractElement的所有报异常的方法都删去:

     1 package composite.qsk;
     2 
     3 import java.util.List;
     4 
     5 public abstract class AbstractElement {
     6 
     7     // 内容(包含在"<X>"和"</X>"之间的部分,没有用“<”和“>”括起来)
     8     protected String content = null;
     9 
    10     // 元素层,根层数为0,其子元素层数为1,依次
    11     private int level = 0;
    12 
    13     // 抽象方法、得到本元素所有内容(类似“<a c=d>efgh </a>”)
    14     public abstract String getAllContent();
    15 
    16     public List<XMLElement> getChildElements()
    17     {
    18         throw new UnsupportedOperationException("对象不支持此功能");
    19     }
    20 
    21     public int getLevel()
    22     {
    23         return level;
    24     }
    25 
    26     public void setLevel(int level)
    27     {
    28         this.level = level;
    29     }
    30 
    31     // 设置本元素内容
    32     public boolean setContent(String content)
    33     {
    34         boolean flag = false;
    35         if (content != null)
    36         {
    37             this.content = content;
    38             flag = true;
    39         }
    40         return flag;
    41     }
    42 
    43     // 得到本元素的内容
    44     public String getContent()
    45     {
    46         return content;
    47     }
    48 
    49 }

    除此之外,只有测试类需要改动,这里就不再演示了。结果没有区别。

  • 相关阅读:
    黑域,黑阈 Permission denied
    手机闪存速度测试工具,AndroBench
    找进程的窗口Handle
    nginx http 正向代理
    windows命令行netstat 统计连接数
    FLIR ONE PRO热成像仪
    python2.0_s12_day14_jQuery详解
    python2.0_s12_day13_javascript&Dom&jQuery
    ssh&scp指定密钥
    apache+php生产环境错误记录
  • 原文地址:https://www.cnblogs.com/zrtqsk/p/3725154.html
Copyright © 2011-2022 走看看