做网站 想做成宽屏的,百度小说排名,泉州手机网站建设,深圳 教育集团网站建设组合模式的应用
组合模式介绍
组合模式(Composite Pattern) 的定义是#xff1a;将对象组合成树形结构以表示整体和部分的层次结构。组合模式可以让用户统一对待单个对象和对象的组合。
比如#xff1a;Windows操作系统中的目录结构#xff0c;通过tree命令实现树形结构展…组合模式的应用
组合模式介绍
组合模式(Composite Pattern) 的定义是将对象组合成树形结构以表示整体和部分的层次结构。组合模式可以让用户统一对待单个对象和对象的组合。
比如Windows操作系统中的目录结构通过tree命令实现树形结构展示。 在上图中包含了文件夹和文件两类不同元素其中在文件夹中可以包含文件还可以继续包含子文件夹。子文件夹中可以放入文件也可以放入子文件夹。 文件夹形成了一种容器结构树形结构递归结构。 尽管文件夹和文件是不同类型的对象它们有一个共性就是都可以被放入文件夹中。文件和文件夹可以被当做是同一种对象看待。
组合模式其实就是将一组对象文件夹和文件组织成树形结构以表示一种“部分-整体”的层次结构目录与子目录的嵌套结构。组合模式让客户端可以统一处理单个对象文件和组合对象文件夹的逻辑递归遍历。
组合模式更像是一种数据结构和算法的抽象数据可以表示成树这种数据结构业务需求可以通过在树上的递归遍历算法来实现。 组合模式主要包含三种角色 抽象根节点Component定义系统各层次对象的共有方法和属性可以预先定义一些默认行为和属性。 包含所有子类共有行为的声明和实现。在抽象根节点中定义了访问及管理子构件的方法如增加子节点、删除子节点、获取子节点等。 树枝节点Composite定义树枝节点的行为存储子节点组合树枝节点和叶子节点形成一个树形结构。 树枝节点可以包含树枝节点也可以包含叶子节点。它其中有一个集合可以用于存储子节点包含在抽象根节点中定义的行为。业务方法中可以递归调用其子节点的业务方法。 叶子节点Leaf叶子节点对象其下再无分支是系统层次遍历的最小单位。 叶子节点没有子节点包含在抽象根节点中定义的行为。
组合模式示例
程序功能列出某一目录下所有的文件和文件夹。
类图如下 我们按照下图的表示进行文件和文件夹的构建。 Entry类: 抽象类用来定义File类和Directory类的共性内容
/*** Entry抽象类,表示目录条目(文件文件夹)的抽象类*/
public abstract class Entry {public abstract String getName(); // 获取文件名public abstract int getSize(); // 获取文件大小// 添加文件夹或文件public abstract Entry add(Entry entry);// 显示指定目录下的所有信息public abstract void printList(String prefix);Overridepublic String toString() {return getName() ( getSize() );}
}File类: 叶子节点表示文件
/*** File类 表示文件*/
public class File extends Entry {private String name; // 文件名private int size; // 文件大小public File(String name, int size) {this.name name;this.size size;}Overridepublic String getName() {return name;}Overridepublic int getSize() {return size;}Overridepublic Entry add(Entry entry) {return null; // 叶子节点不能添加子节点}Overridepublic void printList(String prefix) {System.out.println(prefix / this);}
}Directory类: 树枝节点表示文件夹
/*** Directory表示文件夹*/
public class Directory extends Entry {private String name; // 文件夹名private ArrayListEntry directory new ArrayList(); // 文件夹与文件的集合public Directory(String name) {this.name name;}Overridepublic String getName() {return this.name;}/*** 获取文件大小* 1.如果entry对象是File类型,则调用getSize方法获取文件大小* 2.如果entry对象是Directory类型,会继续调用子文件夹的getSize方法,形成递归调用.*/Overridepublic int getSize() {int size 0;for (Entry entry : directory) {size entry.getSize();}return size;}Overridepublic Entry add(Entry entry) {directory.add(entry);return this;}Overridepublic void printList(String prefix) {System.out.println(prefix / this);for (Entry entry : directory) {entry.printList(prefix / name);}}
}测试代码
public class Client {public static void main(String[] args) {// 根节点Directory rootDir new Directory(root);// 树枝节点Directory binDir new Directory(bin);// 向bin目录中添加叶子节点binDir.add(new File(vi, 10000));binDir.add(new File(test, 20000));Directory tmpDir new Directory(tmp);Directory usrDir new Directory(usr);Directory mysqlDir new Directory(mysql);mysqlDir.add(new File(my.cnf, 30));mysqlDir.add(new File(test.db, 25000));usrDir.add(mysqlDir);rootDir.add(binDir);rootDir.add(tmpDir);rootDir.add(mysqlDir);rootDir.printList();}
}组合模式优点
组合模式可以清楚地定义分层次的复杂对象表示对象的全部或部分层次它让客户端忽略了层次的差异方便对整个层次结构进行控制。在组合模式中增加新的树枝节点和叶子节点都很方便无须对现有类库进行任何修改符合“开闭原则”。组合模式为树形结构的面向对象实现提供了一种灵活的解决方案通过叶子节点和树枝节点的递归组合可以形成复杂的树形结构但对树形结构的控制却非常简单。
组合模式缺点
使用组合模式的前提在于你的业务场景必须能够表示成树形结构。所以组合模式的应用场景也比较局限它并不是一种很常用的设计模式。
组合模式使用场景分析
处理一个树形结构比如公司人员组织架构、订单信息等跨越多个层次结构聚合数据比如统计文件夹下文件总数统一处理一个结构中的多个对象比如遍历文件夹下所有 XML 类型文件内容。
MyBatis中的应用
MyBatis支持动态SQL的强大功能比如下面的这个SQL
update idupdate parameterTypeorg.format.dynamicproxy.mybatis.bean.UserUPDATE userstrim prefixSET prefixOverrides,if testname ! null and name ! name #{name}/ifif testage ! null and age ! , age #{age}/ifif testbirthday ! null and birthday ! , birthday #{birthday}/if/trimwhere id ${id}
/update在这里面使用到了trim、if等动态标签我们可以根据实际的业务需求动态地拼装SQL语句。这些动态SQL标签在MyBatis中被解析后会被转换为不同的SQL节点树结构通过组合模式将这些SQL节点组织在一起最后生成完整的SQL语句。
MyBatis中用组合模式的例子有MixedSqlNode、TrimSqlNode、ChooseSqlNode、IfSqlNode、WhereSqlNode等。
我们通过查看MixedSqlNode类的源码可以看到组合模式的应用。
public class MixedSqlNode implements SqlNode {private final ListSqlNode contents;public MixedSqlNode(ListSqlNode contents) {this.contents contents;}Overridepublic boolean apply(DynamicContext context) {for (SqlNode sqlNode : contents) {sqlNode.apply(context);}return true;}
}在MixedSqlNode类中包含了一个ListSqlNode集合contents它可以包含SqlNode类型的对象如IfSqlNode、TrimSqlNode、WhereSqlNode等。这些节点可以组成一个复杂的树形结构通过递归调用它们的apply方法可以逐步生成完整的SQL语句。
例如IfSqlNode类的源码
public class IfSqlNode implements SqlNode {private final ExpressionEvaluator evaluator;private final String test;private final SqlNode contents;public IfSqlNode(SqlNode contents, String test) {this.test test;this.contents contents;this.evaluator new ExpressionEvaluator();}Overridepublic boolean apply(DynamicContext context) {if (evaluator.evaluateBoolean(test, context.getBindings())) {contents.apply(context);return true;}return false;}
}在IfSqlNode中它包含一个SqlNode类型的contents表示如果条件满足时需要执行的SQL节点。通过调用contents.apply(context)可以将子节点的内容拼接到当前的SQL上下文中。
总结
组合模式在处理复杂结构时非常有用尤其是树形结构和递归处理的场景。它可以通过统一接口处理单个对象和组合对象简化了代码的实现和维护。在MyBatis中组合模式被广泛应用于动态SQL的生成过程中通过不同类型的SQL节点组织成树形结构递归地生成最终的SQL语句。
通过以上内容我们了解了组合模式的定义、结构、优缺点以及在实际中的应用特别是在MyBatis中的具体实现。掌握组合模式可以帮助我们更好地设计和实现复杂结构的代码提高代码的可维护性和扩展性。