前言
设计模式可能是博客圈最热门的话题之一。但是,用来说明每个设计模式的例子通常不是很形象。为了挽救这一点,这篇博客将用一个简单有效的例子来解释组合模式。
我们不会再重复解释这个模型的概念。唯一需要记住的是组合模式通常用在一个树结构的递归操作上。
组合模式例子
假设有一栋建筑,这个建筑有几层楼,每层楼有几个房间。
这个建筑的神奇之处在于,它没有一个总开关。因此,当需要关闭或是开启整栋楼的灯时,就不得不逐层逐个房间按动开关。
为了改变这种情况,我们需要首先定义一个包含开关灯操作的基本接口。这个接口我们命名为Component,对应于组合模式中的Component。
1 2 3 4
| public interface Component { void switchLightsOn(); void switchLightsOff(); }
|
接着,我们定义表示建筑的类Building,Floor和Room。每个类实现该接口,并且实现的逻辑如下:
- Building的开关灯操作意味着整栋楼都将开灯或关灯
- Floor的开关灯操作意味着整层楼的开灯或关灯
- Room的开关灯操作意味着该房间的开灯或关灯
以下是三个类的内容:
Building
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Building extends ArrayList<Floor> implements Component{ @Override public void switchLightsOn() { for (Floor floor : this) { floor.switchLightsOn(); } } @Override public void switchLightsOff() { for (Floor floor : this) { floor.switchLightsOff(); } } }
|
Floor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Floor extends ArrayList<Room> implements Component { private int floorNumber; public Floor(int floorNumber){ this.floorNumber=floorNumber; } @Override public void switchLightsOn() { for (Room room : this) { room.switchLightsOn(); } } @Override public void switchLightsOff() { for (Room room : this) { room.switchLightsOff(); } } }
|
Room
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Room implements Component { private boolean lightsOn = false; private int roomNumber; public Room(int roomNumber){ this.roomNumber=roomNumber; } @Override public void switchLightsOn() { lightsOn = true; } @Override public void switchLightsOff() { lightsOn = false; } public boolean isLightsOn() { return lightsOn; } }
|
补充说明一下:
- 出于方便,Building类和Floor类直接继承了ArrayList来获得其容器的功能
- Building将关灯的操作传递给其下所有的楼层。类似的,每个楼层将关灯的操作传递给每个房间。这种递归传递时组合模式独有的一个特点。
- 总体的效果是Building上的行为启动了一系列操作并传递给Floors和Rooms。这种多米诺骨牌效应也是组合模式的一个特点。
看一下具体的运行情况。首先,我们需要新建一个Building(默认情况下,灯是关闭状态)。之后,调用建筑的switchLightsOn方法,打开建筑中的所有房间的灯。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public class CompositeTest { private Building building; @Before public void createBuilding(){ building = new Building(); Floor floor = new Floor(1); floor.add(new Room(11)); floor.add(new Room(12)); building.add(floor); floor = new Floor(2); floor.add(new Room(21)); floor.add(new Room(22)); floor.add(new Room(23)); building.add(floor); floor = new Floor(3); floor.add(new Room(31)); floor.add(new Room(32)); floor.add(new Room(33)); building.add(floor); } @Test public void buildingLightsAreOn(){ for(Floor floor : building){ for(Room room : floor){ assertEquals(false,room.isLightsOn()); } } building.switchLightsOn(); for(Floor floor : building){ for(Room room : floor){ assertEquals(true,room.isLightsOn()); } } } }
|
原文链接: https://dzone.com/articles/using-the-composite-pattern-to-turn-the-lights-on