1. 1 不可撤销
  2. 2 小年兽 程嘉敏
  3. 3 手放开 李圣杰
  4. 4 迷人的危险3(翻自 dance flow) FAFA
  5. 5 山楂树之恋 程佳佳
  6. 6 summertime cinnamons / evening cinema
  7. 7 不谓侠(Cover 萧忆情Alex) CRITTY
  8. 8 神武醉相思(翻自 优我女团) 双笙
  9. 9 空山新雨后 音阙诗听 / 锦零
  10. 10 Wonderful U (Demo Version) AGA
  11. 11 广寒宫 丸子呦
  12. 12 陪我看日出 回音哥
  13. 13 春夏秋冬的你 王宇良
  14. 14 世界が终わるまでは… WANDS
  15. 15 多想在平庸的生活拥抱你 隔壁老樊
  16. 16 千禧 徐秉龙
  17. 17 我的一个道姑朋友 双笙
  18. 18 大鱼  (Cover 周深) 双笙
  19. 19 霜雪千年(Cover 洛天依 / 乐正绫) 双笙 / 封茗囧菌
  20. 20 云烟成雨(翻自 房东的猫) 周玥
  21. 21 情深深雨濛濛 杨胖雨
  22. 22 Five Hundred Miles Justin Timberlake / Carey Mulligan / Stark Sands
  23. 23 斑马斑马 房东的猫
  24. 24 See You Again Wiz Khalifa / Charlie Puth
  25. 25 Faded Alan Walker / Iselin Solheim
  26. 26 Natural J.Fla
  27. 27 New Soul Vox Angeli
  28. 28 ハレハレヤ(朗朗晴天)(翻自 v flower) 猫瑾
  29. 29 像鱼 王贰浪
  30. 30 Bye Bye Bye Lovestoned
  31. 31 Blame You 眠 / Lopu$
  32. 32 Believer J.Fla
  33. 33 书信 戴羽彤
  34. 34 柴 鱼 の c a l l i n g【已售】 幸子小姐拜托了
  35. 35 夜空中最亮的星(翻自 逃跑计划) 戴羽彤
  36. 36 慢慢喜欢你 LIve版(翻自 莫文蔚) 戴羽彤
  37. 37 病变(翻自 cubi) 戴羽彤
  38. 38 那女孩对我说 (完整版) Uu
  39. 39 绿色 陈雪凝
  40. 40 月牙湾 LIve版(翻自 F.I.R.) 戴羽彤
夜空中最亮的星(翻自 逃跑计划) - 戴羽彤
00:00 / 04:10

夜空中最亮的星 能否听清

那仰望的人 心底的孤独和叹息

夜空中最亮的星 能否记起

那曾与我同行 消失在风里的身影

我祈祷拥有一颗透明的心灵

和会流泪的眼睛

给我再去相信的勇气

越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请指引我靠近你

夜空中最亮的星 是否知道

那曾与我同行的身影 如今在哪里

夜空中最亮的星 是否在意

是等太阳先升起 还是意外先来临

我宁愿所有痛苦都留在心底

也不愿忘记你的眼睛

哦 给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行 哒~

我祈祷拥有一颗透明的心灵

和会流泪的眼睛 哦

给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行

设计模式详解——组合模式

前言

今天我们分享的这个设计模式,用一句话来概括的话,就是化零为整,再进一步解释就是,通过这个设计模式,我们可以像操作一个对象一样操作一个对象的集合,不过这个对象在组合模式中被称作叶节点,而对象的集合被称为组合,而这个结合本身也是也节点的树形结构的集合。是不是感觉越来越绕了呢?没关系,下面我就来详细看下组合模式的基本原理和具体实现。

组合模式

组合模式允许我们将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

使用场景

  • 想表示对象的部分-整体层次结构(树形结构)。

  • 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

要点

  • 组合模式让我们能用树形方式创建对象的结构,树里面包含了组合以及个别的对象
  • 使用组合模式,我们能把相同的操作应用到组合和个别对象上。换句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。

示例

下面我们通过一个具体实例来演示下组合模式到底是如何工作的。这里我们直接用了《Head First设计模式》上的示例,是对餐厅菜单的模拟,只不过我引入了一个通用接口。

组合接口

首先是组合的接口,这个接口不论是叶节点还是叶节点组合都需要继承,不过都不是直接继承。

public interface Component {
    void add(Component component);
    void remove(Component component);
    Component getChild(int i);
}
组合抽象类

这个抽象类就是给叶节点和节点组合继承的,其中方法都有了默认实现,默认都抛出了UnsupportedOperationException

public abstract class MenuComponent implements Component {
    @Override
    public void add(Component component) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void remove(Component component) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Component getChild(int i) {
        throw new UnsupportedOperationException();
    }

    public String getName() {
        throw new UnsupportedOperationException();
    }

    public String getDescription() {
        throw new UnsupportedOperationException();
    }

    public double getPrice() {
        throw new UnsupportedOperationException();
    }

    public boolean isVegetarian() {
        throw new UnsupportedOperationException();
    }

    public void print() {
        throw new UnsupportedOperationException();
    }

}
叶节点实现

这里的叶节点主要覆写了父类的getNamegetDescriptionisVegetariangetPrice等方法,这些方法也主要是针对具体菜单的

public class MenuItem extends MenuComponent {
    private String name;
    private String description;
    private boolean vegetarian;
    private double price;

    public MenuItem(String name, String description, boolean vegetarian, double price) {
        this.name = name;
        this.description = description;
        this.vegetarian = vegetarian;
        this.price = price;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public boolean isVegetarian() {
        return vegetarian;
    }

    @Override
    public double getPrice() {
        return price;
    }

    @Override
    public void print() {
        System.out.println("==========start=============");
        System.out.printf("name: %s  price: ¥%s%n", this.getName(), this.getPrice());
        System.out.printf("description: %s  isVegetarian: %s%n", this.getDescription(), this.isVegetarian());
        System.out.println("==========end=============");
    }
}
节点组合实现

因为节点组合要管理叶节点,所以这里主要实现了addremovegetChild等方法,当然也实现了getNamegetDescription等基础方法:

public class Menu extends MenuComponent {
    ArrayList<Component> menuComponents = new ArrayList<>();
    String name;
    String description;

    public Menu(String name, String description) {
        this.name = name;
        this.description = description;
    }

    @Override
    public void add(Component component) {
        menuComponents.add(component);
    }

    @Override
    public void remove(Component component) {
        menuComponents.remove(component);
    }

    @Override
    public Component getChild(int i) {
        return menuComponents.get(i);
    }

    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public String getDescription() {
        return super.getDescription();
    }

    @Override
    public void print() {
        System.out.println("==========start=============");
        System.out.printf("name: %s", this.getName());
        System.out.printf("description: %s", this.getDescription());
        System.out.println("==========child start=============");
        Iterator<Component> iterator = menuComponents.iterator();
        while (iterator.hasNext()) {
            MenuComponent component = (MenuComponent)iterator.next();
            component.print();
        }
        System.out.println("==========child end=============");
        System.out.println("============end===========");
    }
}
测试代码

下面我们开始编写测试代码。这里我们分别构造了多个叶节点,并将其中一部分组成节点组合,最后分别执行叶节点和子节点的print方法(这里的print方法其实就是我们设计模式原理图中的operation方法)

    @Test
    public void testComponent() {

        // 叶节点
        MenuItem slr = new MenuItem("烧鹿茸", "好吃美味,价格实惠", Boolean.FALSE, 180.0);
        MenuItem sxz = new MenuItem("烧熊掌", "好吃美味,价格实惠", Boolean.FALSE, 190.0);

        MenuItem hsr = new MenuItem("红烧肉", "好吃美味,价格实惠", Boolean.FALSE, 36.0);
        MenuItem hsqz = new MenuItem("红烧茄子", "好吃美味,价格实惠", Boolean.TRUE, 14.0);
        MenuItem hsjk = new MenuItem("红烧鸡块", "好吃美味,价格实惠", Boolean.FALSE, 38.0);
        MenuItem yxrs = new MenuItem("鱼香肉丝", "好吃美味,价格实惠", Boolean.FALSE, 22.0);
        MenuItem ssbc = new MenuItem("手撕包菜", "好吃美味,价格实惠", Boolean.TRUE, 12.0);

        // 组合节点
        Menu menu = new Menu("家常菜", "美味家常菜");
        menu.add(hsr);
        menu.add(hsqz);
        menu.add(hsjk);
        menu.add(yxrs);
        menu.add(ssbc);
        // 子节点print方法
        slr.print();
        sxz.print();
        // 组合节点print方法
        menu.print();

    }
运行结果

总结

想必通过上面的示例,各位小伙伴已经对组合模式有了一定的认知,对这种设计模式适用的场景也有了比较明确认识:如果在一个业务中,单个对象和对象的集合需要具备同样的类型和方法,那组合模式就是最佳选择,比如我们这里的菜单和菜单组合,当然,更具体的应用场景,还需要各位小伙伴结合具体应用场景分析,但是学习的时候多思考应用场景才是学习正在的目的。好了,今天就到这里吧!

posted @ 2021-10-23 22:30  云中志  阅读(258)  评论(0编辑  收藏  举报