资讯专栏INFORMATION COLUMN

猫头鹰的深夜翻译:使用组合模式来开关灯

elina / 2398人阅读

摘要:为了挽救这一点,这篇博客将用一个简单有效的例子来解释组合模式。唯一需要记住的是组合模式通常用在一个树结构的递归操作上。这个接口我们命名为,对应于组合模式中的。这种多米诺骨牌效应也是组合模式的一个特点。

前言

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

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

组合模式例子

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

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

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

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

Building的开关灯操作意味着整栋楼都将开灯或关灯

Floor的开关灯操作意味着整层楼的开灯或关灯

Room的开关灯操作意味着该房间的开灯或关灯

以下是三个类的内容:

Building
public class Building extends ArrayList 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 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());
         }
      }
   }
}


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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68520.html

相关文章

  • 头鹰深夜翻译:分布式系统Toolkit模式

    摘要:根本上来说,这意味着不仅要将整个应用程序分解,而且要将任何一个服务器中的各个部分分解为多个模块化容器,这些容器易于参数化和重复使用。在中,这种模块化容器服务的实施者是。一个是指一组共享文件系统,内核命名空间和地址的一组容器。 过去几年容器逐渐成为了打包和部署代码的流行的方式。容器镜像解决很多现有的打包和部署工具所带来的问题,初次以外,还为我们提供了构建分布式应用的全新的思路。就如SOA...

    hiyayiji 评论0 收藏0
  • 头鹰深夜翻译:请不要把它叫做Restful!

    摘要:因此,误解几乎是与之俱来的。这是完全错误的。就像所强调的,对于一个被称作的来说,状态转移管理是一个必须要完成的需求。你可以将其称为或是,但是请不要把它叫做。 2000年的时候,Douglas Crockford声明JavaScript是最被误解的编程语言。这种误解来源于不良的命名规范,错误设计,非标准模式等等。因此,误解几乎是与之俱来的。 我也在关于Restful架构上发表了一个相似的...

    dadong 评论0 收藏0
  • 头鹰深夜翻译:Java 2D Graphics, 简单仿射变换

    摘要:什么是仿射变换一组设备无关的坐标被用来将所有的坐标信息传递给对象。对象作为对象状态的一部分。类代表一个的仿射变化,将一组的坐标进行线性映射到另一组保留了平行关系和竖直关系的坐标中。 什么是仿射变换 一组设备无关的坐标被用来将所有的坐标信息传递给Graphics2D对象。AffineTransform对象作为Graphics2D对象状态的一部分。该对象定义了如何将用户空间的坐标转化为设备...

    whinc 评论0 收藏0
  • 头鹰深夜翻译:BlockingQueue和持续管理

    摘要:我们将使用单个线程管理任务放入队列的操作以及从队列中取出的操作。同时这个线程会持续的管理队列。另一个线程将用来创建,它将一直运行知道服务器终止。此线程永远不会过期,有助于实现持续监控。这些请求将会自动的被获取,并在线程中继续处理。 在Java中,BlockingQueue接口位于java.util.concurrent包下。阻塞队列主要用来线程安全的实现生产者-消费者模型。他们可以使用...

    YanceyOfficial 评论0 收藏0
  • 头鹰深夜翻译:为何需要缓存以及如何实现缓存

    摘要:由于需要跨进程访问网络上的高速缓存,因此延迟,故障和对象序列化会导致性能下降。应用程序高速缓存会自动清除条目以保持其内存占用。缓存统计高速缓存统计信息可帮助识别高速缓存的运行状况并提供有关高速缓存行为和性能的信息。 前言 这篇文章探索了现有的各种JAVA缓存基数,它们对各种场景下提高应用的性能起着重要的作用。 近十年来,信息技术极高的提升了业务流程,它已经成为了全球企业的战略性方案。它...

    FuisonDesign 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<