"一种方法应该做一件事,一次只做一次" - 那是什么意思?

时间:2018-04-17 06:57:44

标签: oop methods coding-style

  

SRP:"它说你的班级或方法应该只做一件事"

我什么时候知道我的方法不止一件事? 例: 我的课程Bus中包含List<Passenger>和枚举BusStateBus的状态取决于List<Passenger>的大小。

public void addPassenger(Passenger p){
    this.passengerList.add(p);
    if (passengerList.size < 10)
       this.state = BusState.EMPTY;
    else if (passengerList.size < 30)
      this.state = BusState.HALF_FULL;
    else if (passengerList.size >= 30)
      this.state = BusState.FULL;
}

即使我重构了这个:

public void addPassenger(Passenger p){
    this.passengerList.add(p);
    changeBusState();
}

private void changeBusState(){
    if (passengerList.size < 10)
       this.state = BusState.EMPTY;
    else if (passengerList.size < 30)
      this.state = BusState.HALF_FULL;
    else if (passengerList.size >= 30)
      this.state = BusState.FULL;
}

在我看来,方法addPassenger()做的不止一件事:
- 在列表中添加新乘客
- 检查当前的乘客人数
- 必要时改变公交车的状态

我如何理解SRP?这种方法不止一件事吗?

2 个答案:

答案 0 :(得分:2)

我同意addPassenger做的不止一件事。

使其只做一件事的一种方法是删除state字段并使用getState方法根据有多少乘客返回状态(假设您使用Java编写并且BusState是一个枚举):

public BusState getState() {
    if (passengerList.size < 10)
        return BusState.EMPTY;
    else if (passengerList.size < 30)
        return BusState.HALF_FULL;
    else if (passengerList.size >= 30)
        return BusState.FULL;
    else
        return BusState.UNKNOWN; // somehow the no. of passengers is negative? You can consider throwing an exception here as well...
}

答案 1 :(得分:1)

罗伯特·马丁解释了&#34;一件事&#34;作为&#34;改变的一个商业理由&#34;。没有通用的定义&#34;一个&#34;对于所有代码库,因为我们创建的API在不同的抽象级别上工作。所以这一切都取决于谁是你班级的客户,以及他们可能需要做出哪些改变。

在你的情况下,有意义地说该方法正在做两件事:它管理总线的内容并计算状态。因此,它有两个原因需要改变:

  • 添加乘客的不同业务逻辑:例如,有人可能希望验证公交车上是否有足够的地方可供另一位乘客使用,如果没有则抛出异常

  • 关于BusState语义的不同业务逻辑(最简单的例子:一个人可能希望从31名乘客开始,而不是30名乘客)

在此上下文中,您可以更改addPassenger以专注于仅添加:

public void addPassenger(Passenger p){
    this.passengerList.add(p);
}

并更改BusState getter以按需执行计算(类似于Sweeper中提出的their answer):

public BusState getBusState() {
    if (passengerList.size < 10)
        return BusState.EMPTY;
    else if (passengerList.size < 30)
        return BusState.HALF_FULL;
    else if (passengerList.size >= 30)
        return BusState.FULL;
    else
        throw ...
}