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

猜你喜欢

转载自www.cnblogs.com/lvbinbin2yujie/p/10624630.html
今日推荐