2

前言

设计模式可能是博客圈最热门的话题之一。但是,用来说明每个设计模式的例子通常不是很形象。为了挽救这一点,这篇博客将用一个简单有效的例子来解释组合模式

我们不会再重复解释这个模型的概念。唯一需要记住的是组合模式通常用在一个树结构的递归操作上。

组合模式例子

假设有一栋建筑,这个建筑有几层楼,每层楼有几个房间。
这个建筑的神奇之处在于,它没有一个总开关。因此,当需要关闭或是开启整栋楼的灯时,就不得不逐层逐个房间按动开关。

为了改变这种情况,我们需要首先定义一个包含开关灯操作的基本接口。这个接口我们命名为Component,对应于组合模式中的Component

public interface Component {
   void switchLightsOn();
   void switchLightsOff();
}

接着,我们定义表示建筑的类Building,Floor和Room。每个类实现该接口,并且实现的逻辑如下:

  • Building的开关灯操作意味着整栋楼都将开灯或关灯
  • Floor的开关灯操作意味着整层楼的开灯或关灯
  • Room的开关灯操作意味着该房间的开灯或关灯

以下是三个类的内容:

Building

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

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

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方法,打开建筑中的所有房间的灯。

public class CompositeTest {
   private Building building;
   @Before
   public void createBuilding(){
      building = new Building();
      //1st floor
      Floor floor = new Floor(1);
      floor.add(new Room(11));
      floor.add(new Room(12));
      building.add(floor);
      //2nd floor
      floor = new Floor(2);
      floor.add(new Room(21));
      floor.add(new Room(22));
      floor.add(new Room(23));
      building.add(floor);
      //3rd 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(){
       //checking that all rooms are off
      for(Floor floor : building){
         for(Room room : floor){
            assertEquals(false,room.isLightsOn());
         }
      }
      building.switchLightsOn();
       //checking that all rooms are on
      for(Floor floor : building){
         for(Room room : floor){
            assertEquals(true,room.isLightsOn());
         }
      }
   }
}

clipboard.png
想要了解更多开发技术,面试教程以及互联网公司内推,欢迎关注我的微信公众号!将会不定期的发放福利哦~


raledong
2.7k 声望2k 粉丝

心怀远方,负重前行