zoukankan      html  css  js  c++  java
  • java设计模式--合成模式

    合成模式,又有叫 组合模式的 , 也有叫 部分-整体模式的,反正叫啥都好,总离不开 Composite 这个单词。

    图解设计模式一书中,将合成模式归纳在 “一致性”一栏,合成模式的设计意图是  能够使容器与内容具有一致性,再通俗点就是  保证调用单对象与组合对象的一致性。

     image

    合成模式UML类图如上

    Component(抽象构件):抽象类或者接口,给出公共的行为;

    Leaf(树叶构件):树叶构件一般不需要下级角色了,代表各色各样具体的抽象构件的实现类;

    Composite(树枝构件):就像树枝上挂着一些列抽象构件,可能是叶子,也可能还挂着树枝。树枝构件维护着抽象构件的组合,而不单单是树叶构件的组合。

    最常见的合成模式可能就是:计算机文件系统,目录下面可能存文件,可能存文件夹,文件夹里面呢,可以存一堆目录;

    以文件系统记录一个例子:

      把目录抽象出来作为抽象构件,文件作为树叶构件,而文件夹作为树枝构件;

    目录Entry:

    public abstract class Entry {
        public abstract String getName();
        public  abstract int getSize();
        public Entry add(Entry entry) throws Exception{
            throw new RuntimeException("我没法添加目录条目");
        }
        public void printList(){
            printList("");
        }
    
        protected abstract void printList(String prefix);
    
        @Override
        public String toString() {
            return getName()+"("+getSize()+")";
        }
    }

    文件File:

    public class File extends Entry{
    
        private String name;
        private int size;
    
        public File(String name, int size) {
            this.name = name;
            this.size = size;
        }
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public int getSize() {
            return size;
        }
    
        @Override
        protected void printList(String prefix) {
            System.out.println(prefix+"/"+this);
        }
    }

    文件夹Directory:

    public class Directory extends Entry{
        private String name;
    
        public Directory(String name) {
            this.name = name;
        }
    
        private ArrayList directory=new ArrayList();
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public int getSize() {
            int size=0;
            Iterator iterator = directory.iterator();
            while(iterator.hasNext()){
                Entry entry = (Entry) iterator.next();
                size+=entry.getSize();
            }
            return size;
        }
    
        @Override
        public Entry add(Entry entry) throws Exception {
            directory.add(entry);
            return this;
        }
    
        @Override
        protected void printList(String prefix) {
            System.out.println(prefix+"/"+this);
            Iterator iterator = directory.iterator();
            while(iterator.hasNext()){
                Entry entry = (Entry) iterator.next();
                entry.printList(prefix+"/"+name);
            }
    
        }
    }

    测试方法:

    public static void main(String[] args) {
            System.out.println("Making root entries....");
            Directory root=new Directory("root");
            Directory bin=new Directory("bin");
            Directory tmp=new Directory("tmp");
            Directory usr=new Directory("usr");
            try {
                root.add(bin);
                root.add(tmp);
                root.add(usr);
                File vi = new File("vi", 10000);
                bin.add(vi);
                bin.add(new File("latex",20000));
    
                root.printList();
    
                System.out.println("");
                System.out.println("Making user entries....");
                Directory yuki=new Directory("yuki");
                Directory hanako=new Directory("hanako");
                Directory tomura=new Directory("tomura");
                usr.add(yuki);
                usr.add(hanako);
                usr.add(tomura);
               yuki.add(new File("diary.html",100));
                File javaFile = new File("Composite.java", 200);
                yuki.add(javaFile);
                hanako.add(new File("memo.tex",300));
                tomura.add(new File("game.doc",400));
                tomura.add(new File("junk.mail",500));
                root.printList();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    }

    输出结果:

    image

    我们通过getSize方法时候,不需要关心这是个File还是Directory,这就是容器与内容一致性的体现。 另外,文件系统可以获取文件当前绝对路径,程序需要改造下:

    Entry类增加方法设置上级目录方法以及获取路径方法:

    image

    File类具体实现方法:

    image

    Directory类改造方法:

    image

    这样就是一个简略的文件的系统,支持获取文件绝对路径。

    image

    合成模式又被分为透明式合成模式、安全式合成模式

    上例 Entry中有add(Entry  entry)这样一个接口暴露出来,我们就有可能 在一个文件里添加一个文件,就可能出现程序错误,这就是不安全的合成模式,透明合成模式;透明合成模式将所有的接口方法都作为Component抽象构件的方法来设计;

    而安全式合成模式呢,就是将add方法移到Directory类中实现,SpringMvc中的HandlerMethodArgumentResolverComposite就是采用安全式合成模式;

    无论哪种设计模式,容器与内容对外都要体现一致性。 比如文件和文件夹删除,我调用文件的删除方法,把这个文件删除即可,删除文件夹,遍历文件夹维护的那个抽象构件集合,递归删除。

    Spring中合成模式一瞥

    Spring中经常可见某个类后缀为Composite,看起来给人一眼就是合成模式的感觉。

    SpringMvc中有这样一个接口HandlerMethodArgumentResolver,作用就是用来解析@RequestMapping方法入参。 HandlerMethodArgumentResolver作为抽象构件,

    public interface HandlerMethodArgumentResolver {
    
    	boolean supportsParameter(MethodParameter parameter);
    
    	
    	Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
    			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
    }

    树叶构件就是HandlerMethodArgumentResolver接口的一大堆实现类,解析各种各样的 方法入参,HandlerMethodArgumentResolverComposite就是树枝构件,维护着一个HandlerMethodArgumentResolver的集合,并且将添加抽象构件的方法封装到了HandlerMethodArgumentResolverComposite内部,属于安全式合成模式。

    想要对方法入参进行解析,调用HandlerMethodArgumentResolverComposite遍历HandlerMethodArgumentResolver集合进行解析,和遍历HandlerMethodArgumentResolver进行解析时一致的。

    image

  • 相关阅读:
    1257: [CQOI2007]余数之和
    BZOJ1036[ZJOI2008]树的统计——树链剖分+线段树
    BZOJ4822[Cqoi2017]老C的任务——树状数组(二维数点)
    BZOJ4196[Noi2015]软件包管理器——树链剖分+线段树
    BZOJ4034[HAOI2015]树上操作——树链剖分+线段树
    BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra
    BZOJ2120&2453数颜色——线段树套平衡树(treap)+set/带修改莫队
    BZOJ2141排队——树状数组套权值线段树(带修改的主席树)
    初探莫比乌斯反演及欧拉反演
    BZOJ1146[CTSC2008]网络管理——出栈入栈序+树状数组套主席树
  • 原文地址:https://www.cnblogs.com/lvbinbin2yujie/p/10624630.html
Copyright © 2011-2022 走看看