精华内容
下载资源
问答
  • 11.4 透明组合模式与安全组合模式通过引入组合模式,Sunny公司设计的杀毒软件具有良好的可扩展性,在增加新的文件类型时,无须修改现有类库代码,只需增加一个新的文件类作为AbstractFile类的子类即可,但是由于在...

    11.4 透明组合模式与安全组合模式

    通过引入组合模式,Sunny公司设计的杀毒软件具有良好的可扩展性,在增加新的文件类型时,无须修改现有类库代码,只需增加一个新的文件类作为AbstractFile类的子类即可,但是由于在AbstractFile中声明了大量用于管理和访问成员构件的方法,例如add()、remove()等方法,我们不得不在新增的文件类中实现这些方法,提供对应的错误提示和异常处理。为了简化代码,我们有以下两个解决方案:

    解决方案一:将叶子构件的add()、remove()等方法的实现代码移至AbstractFile类中,由AbstractFile提供统一的默认实现,代码如下所示:

    //提供默认实现的抽象构件类  
    abstract class AbstractFile {  
        public void add(AbstractFile file) {  
            System.out.println("对不起,不支持该方法!");  
        }  
    
        public void remove(AbstractFile file) {  
            System.out.println("对不起,不支持该方法!");  
        }  
    
        public AbstractFile getChild(int i) {  
            System.out.println("对不起,不支持该方法!");  
            return null;  
        }  
    
        public abstract void killVirus();  
    }  

    如果客户端代码针对抽象类AbstractFile编程,在调用文件对象的这些方法时将出现错误提示。如果不希望出现任何错误提示,我们可以在客户端定义文件对象时不使用抽象层,而直接使用具体叶子构件本身,客户端代码片段如下所示:

    class Client {  
        public static void main(String args[]) {  
            //不能透明处理叶子构件  
            ImageFile file1,file2;  
            TextFile file3,file4;  
            VideoFile file5;  
            AbstractFile folder1,folder2,folder3,folder4;  
            //其他代码省略  
          }  
    }  

    这样就产生了一种不透明的使用方式,即在客户端不能全部针对抽象构件类编程,需要使用具体叶子构件类型来定义叶子对象。

    解决方案二:除此之外,还有一种解决方法是在抽象构件AbstractFile中不声明任何用于访问和管理成员构件的方法,代码如下所示:

    abstract class AbstractFile {  
        public abstract void killVirus();  
    }  

    此时,由于在AbstractFile中没有声明add()、remove()等访问和管理成员的方法,其叶子构件子类无须提供实现;而且无论客户端如何定义叶子构件对象都无法调用到这些方法,不需要做任何错误和异常处理,容器构件再根据需要增加访问和管理成员的方法,但这时候也存在一个问题:客户端不得不使用容器类本身来声明容器构件对象,否则无法访问其中新增的add()、remove()等方法,如果客户端一致性地对待叶子和容器,将会导致容器构件的新增对客户端不可见,客户端代码对于容器构件无法再使用抽象构件来定义,客户端代码片段如下所示:

    class Client {  
        public static void main(String args[]) {  
    
            AbstractFile file1,file2,file3,file4,file5;  
            Folder folder1,folder2,folder3,folder4; //不能透明处理容器构件  
            //其他代码省略  
        }  
    }  

    在使用组合模式时,根据抽象构件类的定义形式,我们可将组合模式分为透明组合模式和安全组合模式两种形式:

    (1) 透明组合模式

    透明组合模式中,抽象构件Component中声明了所有用于管理成员对象的方法,包括add()、remove()以及getChild()等方法,这样做的好处是确保所有的构件类都有相同的接口。在客户端看来,叶子对象与容器对象所提供的方法是一致的,客户端可以相同地对待所有的对象。透明组合模式也是组合模式的标准形式,虽然上面的解决方案一在客户端可以有不透明的实现方法,但是由于在抽象构件中包含add()、remove()等方法,因此它还是透明组合模式,透明组合模式的完整结构如图11-6所示:
    这里写图片描述

    透明组合模式的缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的。叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供add()、remove()以及getChild()等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)。

    (2) 安全组合模式

    安全组合模式中,在抽象构件Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法。这种做法是安全的,因为根本不向叶子对象提供这些管理成员对象的方法,对于叶子对象,客户端不可能调用到这些方法,这就是解决方案二所采用的实现方式。安全组合模式的结构如图11-7所示:
    这里写图片描述

    安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。在实际应用中,安全组合模式的使用频率也非常高,在Java AWT中使用的组合模式就是安全组合模式。

    【作者:刘伟 http://blog.csdn.net/lovelion

    展开全文
  • 1 透明组合模式与安全组合模式 通过引入组合模式,Sunny公司设计的杀毒软件具有良好的可扩展性,在增加新的文件类型时,无须修改现有类库代码,只需增加一个新的文件类作为AbstractFile类的子类即可,但是由于在...

    转载自 树形结构的处理——组合模式(四)

     

    1 透明组合模式与安全组合模式

     

          通过引入组合模式,Sunny公司设计的杀毒软件具有良好的可扩展性,在增加新的文件类型时,无须修改现有类库代码,只需增加一个新的文件类作为AbstractFile类的子类即可,但是由于在AbstractFile中声明了大量用于管理和访问成员构件的方法,例如add()、remove()等方法,我们不得不在新增的文件类中实现这些方法,提供对应的错误提示和异常处理。为了简化代码,我们有以下两个解决方案:

          解决方案一:将叶子构件的add()、remove()等方法的实现代码移至AbstractFile类中,由AbstractFile提供统一的默认实现,代码如下所示:

    [java] view plain copy

    1. //提供默认实现的抽象构件类  
    2. abstract class AbstractFile {  
    3.     public void add(AbstractFile file) {  
    4.         System.out.println("对不起,不支持该方法!");  
    5.     }  
    6.       
    7.     public void remove(AbstractFile file) {  
    8.         System.out.println("对不起,不支持该方法!");  
    9.     }  
    10.       
    11.     public AbstractFile getChild(int i) {  
    12.         System.out.println("对不起,不支持该方法!");  
    13.         return null;  
    14.     }  
    15.       
    16.     public abstract void killVirus();  
    17. }  

          如果客户端代码针对抽象类AbstractFile编程,在调用文件对象的这些方法时将出现错误提示。如果不希望出现任何错误提示,我们可以在客户端定义文件对象时不使用抽象层,而直接使用具体叶子构件本身,客户端代码片段如下所示:

    [java] view plain copy

    1. class Client {  
    2.     public static void main(String args[]) {  
    3.         //不能透明处理叶子构件  
    4.         ImageFile file1,file2;  
    5.         TextFile file3,file4;  
    6.         VideoFile file5;  
    7.         AbstractFile folder1,folder2,folder3,folder4;  
    8.         //其他代码省略  
    9.       }  
    10. }  

          这样就产生了一种不透明的使用方式,即在客户端不能全部针对抽象构件类编程,需要使用具体叶子构件类型来定义叶子对象。

          解决方案二:除此之外,还有一种解决方法是在抽象构件AbstractFile中不声明任何用于访问和管理成员构件的方法,代码如下所示:

    [java] view plain copy

    1. abstract class AbstractFile {  
    2.     public abstract void killVirus();  
    3. }  

          此时,由于在AbstractFile中没有声明add()、remove()等访问和管理成员的方法,其叶子构件子类无须提供实现;而且无论客户端如何定义叶子构件对象都无法调用到这些方法,不需要做任何错误和异常处理,容器构件再根据需要增加访问和管理成员的方法,但这时候也存在一个问题:客户端不得不使用容器类本身来声明容器构件对象,否则无法访问其中新增的add()、remove()等方法,如果客户端一致性地对待叶子和容器,将会导致容器构件的新增对客户端不可见,客户端代码对于容器构件无法再使用抽象构件来定义,客户端代码片段如下所示:

    [java] view plain copy

    1. class Client {  
    2.     public static void main(String args[]) {  
    3.           
    4.         AbstractFile file1,file2,file3,file4,file5;  
    5.         Folder folder1,folder2,folder3,folder4; //不能透明处理容器构件  
    6.         //其他代码省略  
    7.     }  
    8. }  

          在使用组合模式时,根据抽象构件类的定义形式,我们可将组合模式分为透明组合模式和安全组合模式两种形式:

          (1) 透明组合模式

          透明组合模式中,抽象构件Component中声明了所有用于管理成员对象的方法,包括add()、remove()以及getChild()等方法,这样做的好处是确保所有的构件类都有相同的接口。在客户端看来,叶子对象与容器对象所提供的方法是一致的,客户端可以相同地对待所有的对象。透明组合模式也是组合模式的标准形式,虽然上面的解决方案一在客户端可以有不透明的实现方法,但是由于在抽象构件中包含add()、remove()等方法,因此它还是透明组合模式,透明组合模式的完整结构如图11-6所示:

    图11-6  透明组合模式结构图

          透明组合模式的缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的。叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供add()、remove()以及getChild()等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)。

          (2) 安全组合模式

          安全组合模式中,在抽象构件Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法。这种做法是安全的,因为根本不向叶子对象提供这些管理成员对象的方法,对于叶子对象,客户端不可能调用到这些方法,这就是解决方案二所采用的实现方式。安全组合模式的结构如图11-7所示:

    图11-7  安全组合模式结构图

           安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。在实际应用中,安全组合模式的使用频率也非常高,在Java AWT中使用的组合模式就是安全组合模式。

    展开全文
  • java组合模式例子

    2015-01-07 13:49:49
    java组合模式例子
  • 组合模式过程表现了更高水平的安全性。APDU的数据部分不再作为明文传送,而由加密的形式取代,其过程为鉴别模式过程的扩充。  在组合模式过程中,就像在鉴别模式过程中那样,用加密校验和保护的数据对象首先要填补...
  • 设计模式 | 组合模式及典型应用

    千次阅读 多人点赞 2018-10-05 17:36:55
    介绍组合模式 示例 组合模式总结 源码分析组合模式的典型应用 java.awt中的组合模式 Java集合中的组合模式 Mybatis SqlNode中的组合模式 更多内容可访问我的个人博客:http://laijianfeng.org 推荐阅读 设计...

    本文的主要内容:

    • 介绍组合模式
    • 示例
    • 组合模式总结
    • 源码分析组合模式的典型应用
      • java.awt中的组合模式
      • Java集合中的组合模式
      • Mybatis SqlNode中的组合模式

    组合模式

    树形结构不论在生活中或者是开发中都是一种非常常见的结构,一个容器对象(如文件夹)下可以存放多种不同的叶子对象或者容器对象,容器对象与叶子对象之间属性差别可能非常大。

    由于容器对象和叶子对象在功能上的区别,在使用这些对象的代码中必须有区别地对待容器对象和叶子对象,而实际上大多数情况下我们希望一致地处理它们,因为对于这些对象的区别对待将会使得程序非常复杂。

    一个简化的Linux目录树

    组合模式为解决此类问题而诞生,它可以让叶子对象和容器对象的使用具有一致性

    组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有 “整体—部分” 关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为 “整体—部分”(Part-Whole) 模式,它是一种对象结构型模式。

    由于在软件开发中存在大量的树形结构,因此组合模式是一种使用频率较高的结构型设计模式,Java SE中的AWT和Swing包的设计就基于组合模式。

    除此以外,在XML解析、组织结构树处理、文件系统设计等领域,组合模式都得到了广泛应用。

    角色

    Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。

    Leaf(叶子构件):它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。

    Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。

    组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。

    示例

    我们来实现一个简单的目录树,有文件夹和文件两种类型,首先需要一个抽象构件类,声明了文件夹类和文件类需要的方法

    public abstract class Component {
    
        public String getName() {
            throw new UnsupportedOperationException("不支持获取名称操作");
        }
    
        public void add(Component component) {
            throw new UnsupportedOperationException("不支持添加操作");
        }
    
        public void remove(Component component) {
            throw new UnsupportedOperationException("不支持删除操作");
        }
    
        public void print() {
            throw new UnsupportedOperationException("不支持打印操作");
        }
    
        public String getContent() {
            throw new UnsupportedOperationException("不支持获取内容操作");
        }
    }
    

    实现一个文件夹类 Folder,继承 Component,定义一个 List<Component> 类型的componentList属性,用来存储该文件夹下的文件和子文件夹,并实现 getName、add、remove、print等方法

    public class Folder extends Component {
        private String name;
        private List<Component> componentList = new ArrayList<Component>();
    
        public Folder(String name) {
            this.name = name;
        }
    
        @Override
        public String getName() {
            return this.name;
        }
    
        @Override
        public void add(Component component) {
            this.componentList.add(component);
        }
    
        @Override
        public void remove(Component component) {
            this.componentList.remove(component);
        }
    
        @Override
        public void print() {
            System.out.println(this.getName());
            for (Component component : this.componentList) {
                component.print();
            }
        }
    }
    

    文件类 File,继承Component父类,实现 getName、print、getContent等方法

    public class File extends Component {
        private String name;
        private String content;
    
        public File(String name, String content) {
            this.name = name;
            this.content = content;
        }
    
        @Override
        public String getName() {
            return this.name;
        }
    
        @Override
        public void print() {
            System.out.println(this.getName());
        }
    
        @Override
        public String getContent() {
            return this.content;
        }
    }
    

    我们来测试一下

    public class Test {
        public static void main(String[] args) {
            Folder DSFolder = new Folder("设计模式资料");
            File note1 = new File("组合模式笔记.md", "组合模式组合多个对象形成树形结构以表示具有 \"整体—部分\" 关系的层次结构");
            File note2 = new File("工厂方法模式.md", "工厂方法模式定义一个用于创建对象的接口,让子类决定将哪一个类实例化。");
            DSFolder.add(note1);
            DSFolder.add(note2);
    
            Folder codeFolder = new Folder("样例代码");
            File readme = new File("README.md", "# 设计模式示例代码项目");
            Folder srcFolder = new Folder("src");
            File code1 = new File("组合模式示例.java", "这是组合模式的示例代码");
    
            srcFolder.add(code1);
            codeFolder.add(readme);
            codeFolder.add(srcFolder);
            DSFolder.add(codeFolder);
    
            DSFolder.print();
        }
    }
    

    输出结果

    设计模式资料
    组合模式笔记.md
    工厂方法模式.md
    样例代码
    README.md
    src
    组合模式示例.java
    

    输出正常,不过有个小问题,从输出看不出它们的层级结构,为了体现出它们之间的层级关系,我们需要改造一下 Folder 类,增加一个 level 属性,并修改 print 方法

    public class Folder extends Component {
        private String name;
        private List<Component> componentList = new ArrayList<Component>();
        public Integer level;
    
        public Folder(String name) {
            this.name = name;
        }
    
        @Override
        public String getName() {
            return this.name;
        }
    
        @Override
        public void add(Component component) {
            this.componentList.add(component);
        }
    
        @Override
        public void remove(Component component) {
            this.componentList.remove(component);
        }
    
        @Override
        public void print() {
            System.out.println(this.getName());
            if (this.level == null) {
                this.level = 1;
            }
            String prefix = "";
            for (int i = 0; i < this.level; i++) {
                prefix += "\t- ";
            }
            for (Component component : this.componentList) {
                if (component instanceof Folder){
                    ((Folder)component).level = this.level + 1;
                }
                System.out.print(prefix);
                component.print();
            }
            this.level = null;
        }
    }
    

    现在的输出就有相应的层级结构了

    设计模式资料
    	- 组合模式笔记.md
    	- 工厂方法模式.md
    	- 样例代码
    	- 	- README.md
    	- 	- src
    	- 	- 	- 组合模式示例.java
    

    我们可以画出它们之间的类图

    示例.组合模式类图

    在这里父类 Component 是一个抽象构件类,Folder 类是一个容器构件类,File 是一个叶子构件类,Folder 和 File 继承了 Component,Folder 与 Component 又是聚合关系

    透明与安全

    在使用组合模式时,根据抽象构件类的定义形式,我们可将组合模式分为透明组合模式和安
    全组合模式两种形式。

    透明组合模式

    透明组合模式中,抽象构件角色中声明了所有用于管理成员对象的方法,譬如在示例中 Component 声明了 addremove 方法,这样做的好处是确保所有的构件类都有相同的接口。透明组合模式也是组合模式的标准形式。

    透明组合模式的缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的,叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供 add()remove() 等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)

    安全组合模式

    在安全组合模式中,在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在容器构件 Composite 类中声明并实现这些方法。

    安全组合模式模式图

    安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。

    在实际应用中 java.awtswing 中的组合模式即为安全组合模式。

    组合模式总结

    组合模式的主要优点如下:

    • 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
    • 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
    • 在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合“开闭原则”。
    • 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

    组合模式的主要缺点如下:

    • 使得设计更加复杂,客户端需要花更多时间理清类之间的层次关系。
    • 在增加新构件时很难对容器中的构件类型进行限制。

    适用场景

    • 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待它们。
    • 在一个使用面向对象语言开发的系统中需要处理一个树形结构。
    • 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型。

    源码分析组合模式的典型应用

    java.awt中的组合模式

    Java GUI分两种:

    • AWT(Abstract Window Toolkit):抽象窗口工具集,是第一代的Java GUI组件。绘制依赖于底层的操作系统。基本的AWT库处理用户界面元素的方法是把这些元素的创建和行为委托给每个目标平台上(Windows、 Unix、 Macintosh等)的本地GUI工具进行处理。

    • Swing,不依赖于底层细节,是轻量级的组件。现在多是基于Swing来开发。

    我们来看一个AWT的简单示例:

    注意:为了正常显示中文,需要在IDEA中的 Edit Configurations -> VM Options 中设置参数 -Dfile.encoding=GB18030

    import java.awt.*;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    
    public class MyFrame extends Frame {
    
        public MyFrame(String title) {
            super(title);
        }
    
        public static void main(String[] args) {
            MyFrame frame = new MyFrame("这是一个 Frame");
    
            // 定义三个构件,添加到Frame中去
            Button button = new Button("按钮 A");
            Label label = new Label("这是一个 AWT Label!");
            TextField textField = new TextField("这是一个 AWT TextField!");
    
            frame.add(button, BorderLayout.EAST);
            frame.add(label, BorderLayout.SOUTH);
            frame.add(textField, BorderLayout.NORTH);
    
            // 定义一个 Panel,在Panel中添加三个构件,然后再把Panel添加到Frame中去
            Panel panel = new Panel();
            panel.setBackground(Color.pink);
    
            Label lable1 = new Label("用户名");
            TextField textField1 = new TextField("请输入用户名:", 20);
            Button button1 = new Button("确定");
            panel.add(lable1);
            panel.add(textField1);
            panel.add(button1);
    
            frame.add(panel, BorderLayout.CENTER);
    
            // 设置Frame的属性
            frame.setSize(500, 300);
            frame.setBackground(Color.orange);
            // 设置点击关闭事件
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
            frame.setVisible(true);
        }
    }
    

    运行后窗体显示如下

    示例.AWT绘制窗体

    我们在Frame容器中添加了三个不同的构件 ButtonLabelTextField,还添加了一个 Panel 容器,Panel 容器中又添加了 ButtonLabelTextField 三个构件,为什么容器 FramePanel 可以添加类型不同的构件和容器呢?

    我们先来看下AWT Component的类图

    AWT Component类图

    GUI组件根据作用可以分为两种:基本组件和容器组件。

    • 基本组件又称构件,诸如按钮、文本框之类的图形界面元素。
    • 容器是一种比较特殊的组件,可以容纳其他组件,容器如窗口、对话框等。所有的容器类都是 java.awt.Container 的直接或间接子类

    容器父类 Container 的部分代码如下

    public class Container extends Component {
        /**
         * The components in this container.
         * @see #add
         * @see #getComponents
         */
        private java.util.List<Component> component = new ArrayList<>();
        
        public Component add(Component comp) {
            addImpl(comp, null, -1);
            return comp;
        }
        // 省略...
    }
    

    容器父类 Container 内部定义了一个集合用于存储 Component 对象,而容器组件 Container 和 基本组件如 ButtonLabelTextField 等都是 Component 的子类,所以可以很清楚的看到这里应用了组合模式

    Component 类中封装了组件通用的方法和属性,如图形的组件对象、大小、显示位置、前景色和背景色、边界、可见性等,因此许多组件类也就继承了 Component 类的成员方法和成员变量,相应的成员方法包括:

       getComponentAt(int x, int y)
       getFont()
       getForeground()
       getName()
       getSize()
       paint(Graphics g)
       repaint()
       update()
       setVisible(boolean b)
       setSize(Dimension d)
       setName(String name)
    

    Java集合中的组合模式

    HashMap 提供 putAll 的方法,可以将另一个 Map 对象放入自己的存储空间中,如果有相同的 key 值则会覆盖之前的 key 值所对应的 value 值

    public class Test {
        public static void main(String[] args) {
            Map<String, Integer> map1 = new HashMap<String, Integer>();
            map1.put("aa", 1);
            map1.put("bb", 2);
            map1.put("cc", 3);
            System.out.println("map1: " + map1);
    
            Map<String, Integer> map2 = new LinkedMap();
            map2.put("cc", 4);
            map2.put("dd", 5);
            System.out.println("map2: " + map2);
    
            map1.putAll(map2);
            System.out.println("map1.putAll(map2): " + map1);
        }
    }
    

    输出结果

    map1: {aa=1, bb=2, cc=3}
    map2: {cc=4, dd=5}
    map1.putAll(map2): {aa=1, bb=2, cc=4, dd=5}
    

    查看 putAll 源码

        public void putAll(Map<? extends K, ? extends V> m) {
            putMapEntries(m, true);
        }
    

    putAll 接收的参数为父类 Map 类型,所以 HashMap 是一个容器类,Map 的子类为叶子类,当然如果 Map 的其他子类也实现了 putAll 方法,那么它们都既是容器类,又都是叶子类

    同理,ArrayList 中的 addAll(Collection<? extends E> c) 方法也是一个组合模式的应用,在此不做探讨

    Mybatis SqlNode中的组合模式

    MyBatis 的强大特性之一便是它的动态SQL,其通过 if, choose, when, otherwise, trim, where, set, foreach 标签,可组合成非常灵活的SQL语句,从而提高开发人员的效率。

    来几个官方示例:

    动态SQL – IF

    <select id="findActiveBlogLike"  resultType="Blog">
      SELECT * FROM BLOG WHERE state = ‘ACTIVE’ 
      <if test="title != null">
        AND title like #{title}
      </if>
      <if test="author != null and author.name != null">
        AND author_name like #{author.name}
      </if>
    </select>
    

    动态SQL – choose, when, otherwise

    <select id="findActiveBlogLike"  resultType="Blog">
      SELECT * FROM BLOG WHERE state = ‘ACTIVE’
      <choose>
        <when test="title != null">
          AND title like #{title}
        </when>
        <when test="author != null and author.name != null">
          AND author_name like #{author.name}
        </when>
        <otherwise>
          AND featured = 1
        </otherwise>
      </choose>
    </select>
    

    动态SQL – where

    <select id="findActiveBlogLike"  resultType="Blog">
      SELECT * FROM BLOG 
      <where> 
        <if test="state != null">
             state = #{state}
        </if> 
        <if test="title != null">
            AND title like #{title}
        </if>
        <if test="author != null and author.name != null">
            AND author_name like #{author.name}
        </if>
      </where>
    </select>
    

    动态SQL – foreach

    <select id="selectPostIn" resultType="domain.blog.Post">
      SELECT * FROM POST P WHERE ID in
      <foreach item="item" index="index" collection="list"
          open="(" separator="," close=")">
            #{item}
      </foreach>
    </select>
    

    Mybatis在处理动态SQL节点时,应用到了组合设计模式,Mybatis会将映射配置文件中定义的动态SQL节点、文本节点等解析成对应的 SqlNode 实现,并形成树形结构。

    SQLNode 的类图如下所示

    Mybatis SqlNode 类图

    需要先了解 DynamicContext 类的作用:主要用于记录解析动态SQL语句之后产生的SQL语句片段,可以认为它是一个用于记录动态SQL语句解析结果的容器

    抽象构件为 SqlNode 接口,源码如下

    public interface SqlNode {
      boolean apply(DynamicContext context);
    }
    

    applySQLNode 接口中定义的唯一方法,该方法会根据用户传入的实参,参数解析该SQLNode所记录的动态SQL节点,并调用 DynamicContext.appendSql() 方法将解析后的SQL片段追加到 DynamicContext.sqlBuilder 中保存,当SQL节点下所有的 SqlNode 完成解析后,我们就可以从 DynamicContext 中获取一条动态生产的、完整的SQL语句

    然后来看 MixedSqlNode 类的源码

    public class MixedSqlNode implements SqlNode {
      private List<SqlNode> contents;
    
      public MixedSqlNode(List<SqlNode> contents) {
        this.contents = contents;
      }
    
      @Override
      public boolean apply(DynamicContext context) {
        for (SqlNode sqlNode : contents) {
          sqlNode.apply(context);
        }
        return true;
      }
    }
    

    MixedSqlNode 维护了一个 List<SqlNode> 类型的列表,用于存储 SqlNode 对象,apply 方法通过 for循环 遍历 contents 并调用其中对象的 apply 方法,这里跟我们的示例中的 Folder 类中的 print 方法非常类似,很明显 MixedSqlNode 扮演了容器构件角色

    对于其他SqlNode子类的功能,稍微概括如下:

    • TextSqlNode:表示包含 ${} 占位符的动态SQL节点,其 apply 方法会使用 GenericTokenParser 解析 ${} 占位符,并直接替换成用户给定的实际参数值
    • IfSqlNode:对应的是动态SQL节点 <If> 节点,其 apply 方法首先通过 ExpressionEvaluator.evaluateBoolean() 方法检测其 test 表达式是否为 true,然后根据 test 表达式的结果,决定是否执行其子节点的 apply() 方法
    • TrimSqlNode :会根据子节点的解析结果,添加或删除相应的前缀或后缀。
    • WhereSqlNodeSetSqlNode 都继承了 TrimSqlNode
    • ForeachSqlNode:对应 <foreach> 标签,对集合进行迭代
    • 动态SQL中的 <choose><when><otherwise> 分别解析成 ChooseSqlNodeIfSqlNodeMixedSqlNode

    综上,SqlNode 接口有多个实现类,每个实现类对应一个动态SQL节点,其中 SqlNode 扮演抽象构件角色,MixedSqlNode 扮演容器构件角色,其它一般是叶子构件角色

    参考:
    刘伟:设计模式Java版
    慕课网java设计模式精讲 Debug 方式+内存分析
    Java AWT基础及布局管理
    【java源码一带一路系列】之HashMap.putAll()
    徐郡明:Mybatis技术内幕 3.2 SqlNode&SqlSource
    Mybatis 3.4.7 文档:动态 SQL

    更多内容可访问我的个人博客:http://laijianfeng.org
    关注【小旋锋】微信公众号

    推荐阅读

    设计模式 | 简单工厂模式及典型应用
    设计模式 | 工厂方法模式及典型应用
    设计模式 | 抽象工厂模式及典型应用
    设计模式 | 建造者模式及典型应用
    设计模式 | 原型模式及典型应用
    设计模式 | 外观模式及典型应用
    设计模式 | 装饰者模式及典型应用
    设计模式 | 适配器模式及典型应用
    设计模式 | 享元模式及典型应用

    展开全文
  • win10如何进入安全模式删除文件,卸载 1、首先大家进入win10系统,然后使用window键+R组合键点击运行框,写入“msconfig”回车进入系统配置,如下图: 2:以后大家在点击的系统配置中,找到"引导"选项,然后单击,...

    win10如何进入安全模式的两种方式

    第一种:

    1、首先大家进入win10系统,然后使用window键+R组合键点击运行框,写入“msconfig”回车进入系统配置,如下图: 在这里插入图片描述

    2:点击的系统配置中,找到"引导"选项,然后单击,选中window10的引导项,然后在“安全引导”的选项前打上勾,然后打开底部的“确定”保存,如下图。

    在这里插入图片描述

    3:以上设置完后以后,大家重启系统就会自动进去安全模式了,如果要退出安全模式的话,按如上步骤,把安全引导的勾给取消就oK便可,如下图:在这里插入图片描述

    第二种:

    原文链接:https://baijiahao.baidu.com/s?id=1623647621766312474&wfr=spider&for=pc 为了防止链接失效特意截屏

    在这里插入图片描述

    删除文件,卸载

    进入安全模式化就可以随意删除文件,卸载软件

    注:进入安全模式后不会启动任何第三方的软件

    展开全文
  • 组合模式分析前言总结 前言 上一篇,我们介绍了建造者模式,以及建造者模式在源码中的运用,今天我们会先介绍一下责任链模式,然后会再通过一个示例来将责任链模式和建造者模式结合起来应用。 总结 本文介绍了责任链...
  • 有人认为安全很简单,但安全从来都不简单...安全模式本质上也是一种架构模式安全模式安全性与应用系统架构联系起来。安全模式的方法是一种工程方法。本文还以一个非常经典的安全模式PBAC(基于策略的访问控制模式
  • C++ 组合模式

    千次阅读 热门讨论 2017-05-05 20:01:41
    简述 组合模式(Composite Pattern)组合多个对象形成树形结构以表示具有“整体-部分”关系的层次结构。...透明组合模式和安全组合模式 优缺点 适用场景 案例分析 代码实现 透明组合模式 安全组合模式 ...
  • Android中对组合模式的应用,可谓是泛滥成粥,随处可见,那就是View和ViewGroup类的使用。在android UI设计,几乎所有的widget和布局类都依靠这两个类。 组合模式,Composite Pattern,是一个非常巧妙的模式。几乎...
  • 组合模式的定义:又叫作整体-部分(Part-Whole)模式,通过将单个对象(叶节点)和组合对象用相同的接口表示,使客户端对单个对象和组合对象的访问具有一致性。它是一种将对象组合成树状的层次结构的模式。属于结构...
  • JavaScript 设计模式之组合模式

    万次阅读 2019-12-02 22:39:27
    比如公司要给全体员工发放元旦的过节费1000块,这个场景可以运用组合模式,但如果公司给今天过生日的员工发送一封生日祝福的邮件,组合模式在这里就没有用武之地了,除非先把今天过生日的员工挑选出来。只有用一致的...
  • 安全组合模式中,抽象构件Component没有声明任何管理和访问子构件的方法,在具体的实现类中才去定义这些行为。之所以叫“安全”,是因为叶子构件没有子构件,也就不必定义管理访问子构件的方法,对客户端而言,当...
  • JAVA设计模式--组合模式

    万次阅读 2017-02-10 22:14:23
    四、组合模式安全性和透明性 五、组合模式的优缺点 六、总结 一、什么是组合模式 组合(Composite)模式是一种对象的行为模式。将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象...
  • 设计模式之组合模式示例

    千次阅读 2019-11-19 23:17:33
    组合模式简介 组合模式(Composite Pattern),就是同一类型的对象像一棵树一样聚焦在一起。就像下图一样。图中一个结点对应一个类的实例。图中的箭头是“组成关系”,即某个结点内部包含了指向的所有结点。 如果...
  • 【Java设计模式】组合模式

    千次阅读 多人点赞 2019-07-11 11:30:48
    组合模式使客户端对单个对象和组合对象保持一致的方式处理 ◆ 类型:结构型 适用场景 ◆ 希望客户端可以忽略组合对象与单个对象的差异时 ◆ 处理一个树形结构时 优点 ◆ 清楚地定义分层次的复杂对象,表示对象的...
  • java组合模式

    千次阅读 2019-01-23 21:47:28
    组合模式介绍使用场景优点表现形式实例 下面是正文 介绍 组合模式使用户对单个对象和组合对象的使用具有一致性。 屏蔽了容器对象与单个对象在使用时的差异,为客户提供统一的操作接口,从而降低客户代码与被...
  • 组合模式

    千次阅读 2018-05-24 10:42:21
    定义: 将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户能以一致的方式处理个别对象和组合对象。 设计类图: 组合模式中的角色: 列表内容 ...
  • JAVA组合模式

    万次阅读 多人点赞 2018-08-24 00:11:06
    JAVA组合模式 通过本文将学习到 Table of Contents 1、组合模式的概念 2、组合模式的UML图 3、组合模式的实现 4、组合模式的优缺点 5、组合模式适用场景 6、总结 7、关于最近一些事。   红色代表重点,...
  • 设计模型之组合模式含UML完整实例)

    千次阅读 2020-04-14 23:45:42
    设计模型之组合模式 1. 组合模式 1.1 定义与特点   有时又叫作部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象具有一致的访问性。   组合...
  • 组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。  在组合模式中引入了抽象构件类Component,它是...
  • android 7.0 8.0 9.0 10.0去掉系统中的安全模式,防止通过组合键进入到安全模式
  • Java设计模式-组合模式

    千次阅读 2019-03-26 14:54:48
    组合模式
  • 一、基本介绍 组合模式,将对象组合成树形结构以表示“整体-部分”的层次结构,一种对象结构型模式。 由于在软件开发中存在大量的树形结构,因此组合模式是一种使用频率较高的结构型设计模式,Java ...安全组合模式
  • * 24种设计模式——组合模式

    千次阅读 2017-07-28 18:34:02
    将对象组合成树形结构,以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。 一、公司组织架构1(接口篇) 1. 公司人员接口 public interface ICorp { //获取自己的信息(每个员工都...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 237,931
精华内容 95,172
关键字:

安全组合模式