一致性

一、Composite--容器与内容的一致性

1. 场景分析

image.png

2. UML

image.png

3. Code

3.1 抽象父类,一致性的承担者

/**
 * @author CSZ
 */
public abstract class Entry{

    public abstract String getName();
    public abstract int getSize();

    public Entry add(Entry entry) throws FileTreatmentException{
        throw new FileTreatmentException();
    }
    public void printList(){
        printList("");
    }
    protected abstract void printList(String prefix);

    @Override
    public String toString() {
        return getName() + " (" + getSize() + ")";
    }
}

3.2 继承自 Entry 重写了其中的方法

/**
 * @author CSZ
 */
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);
    }
}

3.3 也继承自 Entry 而且扮演容器角色

/**
 * @author CSZ
 */
public class Directory extends Entry{
    private String name;
    // 书中源码没有加入泛型,我认为这里可以直接使用 <Entry> 这样下文中的 Iterator也可以添加泛型而不用强转
    private List directory = new ArrayList();

    public Directory(String name) {
        this.name = name;
    }

    @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){
        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);
        }
    }
}

3.4

/**
 * @author CSZ
 */
public class FileTreatmentException extends RuntimeException{
    public FileTreatmentException() {
    }

    public FileTreatmentException(String message) {
        super(message);
    }
}

3.5 测试类

/**
 * @author CSZ
 */
public class MainTest {
    public static void main(String[] args) {
        try {
            System.out.println("创建根目录");
            Directory rootdir = new Directory("root");
            Directory bindir = new Directory("bin");
            Directory tmpdir = new Directory("tmp");
            Directory usrdir = new Directory("usr");
            rootdir.add(bindir);
            rootdir.add(tmpdir);
            rootdir.add(usrdir);
            bindir.add(new File("vi",10000));
            bindir.add(new File("latex",20000));
            rootdir.printList();

            System.out.println("");
            System.out.println("创建用户目录下");
            Directory yuki = new Directory("yuki");
            Directory hanakao = new Directory("hanakao");
            Directory tomura = new Directory("tomura");
            usrdir.add(yuki);
            usrdir.add(hanakao);
            usrdir.add(tomura);
            yuki.add(new File("diary.html",100));
            hanakao.add(new File("Composite.java",200));
            rootdir.printList();
        } catch (FileTreatmentException e){
            e.printStackTrace();
        }
    }
}
image.png

4. 总结与思考

其实这个关于内容与容器的一致性问题,我们如果使用 linux 的话感受非常明显,而且前面有一个模式中也偷偷使用这个模式,你能不能发现呢?如果没有印象了,告诉你去抽象工厂中找找。
所以没有什么需要太多解释了,不过有一点,我们一定要重视,这个示例中,点睛之笔就是 getName 和 getSize 两个方法,我们为什么可以递归调用,这就是内容和容器的一致性的表现。

二、Decorator 模式--装饰边框与被装饰物的一致性

1. 需求分析

image.png

2. UML

image.png

3. Code

3.1 Display

/**
 * @author CSZ
 */
public abstract class Display {

    public abstract int getColumns();
    public abstract int getRows();
    public abstract String getRowText(int row);
    public final void show(){
        for (int i = 0; i < getRows(); i++) {
            System.out.println(getRowText(i));
        }
    }
}

3.2 StringDisplay


/**
 * @author CSZ
 */
public class StringDisplay extends Display{
    private String string;

    public StringDisplay(String string) {
        this.string = string;
    }

    @Override
    public int getColumns() {
        return string.getBytes().length;
    }

    @Override
    public int getRows() {
        return 1;
    }

    @Override
    public String getRowText(int row) {
        if (row == 0){
            return string;
        } else {
            return null;
        }
    }
}

3.3 Border

/**
 * @author CSZ
 */
public abstract class Border extends Display{
    protected Display display;
    protected Border(Display display){
        this.display = display;
    }
}

3.4 SideBorder


/**
 * @author CSZ
 */
public class SideBorder extends Border{

    private char borderChar;

    public SideBorder(Display display,char ch){
        super(display);
        this.borderChar = ch;
    }

    @Override
    public int getColumns() {
        return 1 + display.getColumns() + 1;
    }

    @Override
    public int getRows() {
        return display.getRows();
    }

    @Override
    public String getRowText(int row) {
        return borderChar + display.getRowText(row) + borderChar;
    }
}

3.5 FullBorder

/**
 * @author CSZ
 */
public class FullBorder extends Border{

    public FullBorder(Display display) {
        super(display);
    }

    @Override
    public int getColumns() {
        return 1 + display.getColumns() + 1;
    }

    @Override
    public int getRows() {
        return 1 + display.getRows() + 1;
    }

    @Override
    public String getRowText(int row) {
        if (row == 0){
            return "+" + makeLine('-',display.getColumns()) + "+";
        }else if (row == display.getRows() + 1){
            return "+" + makeLine('-',display.getColumns()) + "+";
        } else {
            return "|" + display.getRowText(row - 1) + "|";
        }
    }

    private String makeLine(char ch, int count) {
        StringBuffer buffer = new StringBuffer();
        buffer.append(String.valueOf(ch).repeat(Math.max(0, count)));
        return buffer.toString();
    }
}

3.6 MainTest

/**
 * @author CSZ
 */
public class MainTest {

    public static void main(String[] args) {
        Display b1 = new StringDisplay("Hello World");
        Display b2 = new SideBorder(b1, '#');
        Display b3 = new FullBorder(b2);
        b1.show();
        b2.show();
        b3.show();
        Display b4 = new SideBorder(
                new FullBorder(
                        new FullBorder(
                                new SideBorder(
                                        new FullBorder(
                                                new StringDisplay("Peace And Love")),'*'))),'/');
        b4.show();
    }
}
image.png

4. 总结与分析

除了图中的描述分析,还有一些扩展思路

  1. 当我们用巧克力进行了装饰后,得到的仍然是一个蛋糕,这是由于我们的装饰边框与被装饰物具有一致性,体现为 无论是 ConcreteComponent 还是 ConcreteDecorator 都是 Component 的子类。
  2. 当我们裹上厚厚的巧克力酱后,我们仍然可以计算新的蛋糕的半径和高度,也就是被装饰物和装饰物具有相同的接口API,则体现了接口的透明性。
  3. 同时,我们还可以继续撒上糖果,撒上草莓,而我们的蛋糕本体并不需要因为新的变动而变动,这就得益于我们的一致性。更有意思的是再撒上糖果后,我们还可以再涂上巧克力(只要你你不怕变胖)。
  4. 在 java 中 i/o 的处理就是根据这种模式。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容