首页 > 解决方案 > 检查类中方法的存在是否违反了 SOLID 原则?

问题描述

我有一个名为 Bird 的类,它在构造函数中接受鸟类数组。我正在尝试在其中实现一个函数,该函数将检查当前是否有任何鸟在飞行,请记住所有代码都应符合 SOLID 原则。

我有以下两个课程(鹦鹉和鸵鸟)

class Parrot extends FlyingBirds{}   
class Ostrich extends BirdDetail{}

BirdDetail类

abstract class BirdDetail {

  protected $didNotSleepLastNight;

  public function __construct(bool $didNotSleepLastNight)
  {
    $this->didNotSleepLastNight= $didNotSleepLastNight;
  }

  public function didNotSleepLastNight(): bool
  {
    return $this->didNotSleepLastNight;
  }

}

FlyingBirds(不是所有的鸟都会飞,比如鸵鸟)

abstract class FlyingBirds extends BirdDetail{

 protected $isFlyingNow;

 public function __construct(bool $didNotSleepLastNight, bool $isFlyingNow)
 {
    parent::__construct($didNotSleepLastNight);
    $this->isFlyingNow = $isFlyingNow;
 }

 public function isFlyingNow(): bool
 {
    return $this->isFlyingNow;
 }
}   

然后我有一个班级叫Bird

class Bird
{
  private $details;

 public function __construct(array $details)
 {
    $this->details = $details;
 }

 public function didNotSleepLastNight(): bool
 {
    foreach ($this->details as $detail) {

        if ($detail->didNotSleepLastNight()) {
            return true;
        }
    }

    return false;
 }

 public function isFlyingNow(): bool
 {
    foreach ($this->details as $detail) {

        if ($detail->isFlyingNow()) 
        {
            return true;
        }
    }
    return false;
  }
}

现在我将 Parrot 和 Ostrich 的实例传递给 Bird Constructor

$bird = new Bird([new Parrot(true, false), new Ostrich(false)]);     

if($bird->isFlyingNow())
{
 echo "Yes";
}
else
{
 echo "No";
}

问题是上面的代码给了我以下错误

Fatal error: Uncaught Error: Call to undefined method Ostrich::isFlyingNow()

那是因为 Ostrich/BirdDetail 类没有名为 isFlyingNow 的方法。

该问题可以通过将 Birds 类中的 isFlyingNow 方法替换为以下代码来解决:

public function isFlyingNow(): bool
{

    foreach ($this->details as $detail) {

        if (method_exists($detail, 'isFlyingNow') && $detail->isFlyingNow())             
        {
            return true;
        }
    }

    return false;

}

您能否告诉我上述修复是否违反了 SOLID 原则?还是可以用更好的方式解决问题?

标签: phpoopsolid-principlesdesign-principles

解决方案


并没有真正打破 SOLID,只是设计得不太好。

对于更简洁的方法,请使用接口。

由于并非所有鸟类都能飞,因此为所有鸟类提供面向公众的方法isFlying()似乎相当浪费。

也许你可以做这样的事情:

您的基Bird类,您将在其中定义所有鸟类的通用属性和方法。

class Bird {
}

然后,不同的接口来描述 Bird 子类的不同可能行为。有些鸟会飞,有些会游泳,有些会说话,有些会唱歌,有些会潜水,有些会跑,等等。

对于传单:

interface FlyingBird {

    function isFlying():bool;

    function takeOff();

    function land();

    function fly($bearing, $distance);

}

对于谈话者:

interface TalkingBird {

    function say($something);
}

歌手们:

interface SingingBird {
    function sing(array $notes);
}

游泳者(您可能需要区分那些在水面上游泳的人和可以在水面下潜水的人)。

interface SwimmingBird {
   function isSwimming(): bool;
   // etc
}

对于跑步者:

interface RunningBird {
   function isRunning(): bool;
   // etc
}

然后你可以有类似的课程Parrot(苍蝇和谈话,但不做唱歌,跑步或游泳)

class Parrot extends Bird implements TalkingBird, FlyingBird {
    // todo: actual implementation
}

或者Ostrich(可以跑步,但不会游泳、唱歌、说话或飞行):

class Ostrich extend Birds implements RunningBird { /* implementation */}

甚至Penguin(会游泳,不会飞,不会跑,不会唱歌,不会说话):

class Penguin extends Bird implements SwimmingBird { /* implementation */ }

等等等等。整体@package Ornithology正在形成。

这些类的用户应该检查实例是否实现了适当的接口:

if ($birdInstance instanceof FlyingBird && $birdInstance->isFlying()) {
   echo "This bird is flying!";
}

为了简化这些类的组成,您可能需要创建一些特征:

例如

trait FlyingBirdTrait {

    private $flying = false;

    function isFlying():bool {
       return $this->flying;
    }

    function takeOff() {
       $this->flying = true;
    }

    function land() {
       $this->flying = false;
    }

    function fly($bearing, $altitude, $distance) {
       if (!$this->isFlying()) {
           $this->takeOff();
       }
       // calculate new position;

    }
}

然后像这样的类Parrot可以使用:

class Parrot extends Bird implements TalkingBird, FlyingBird {
    uses FlyingBirdTrait;
    // rest of the implementation, etc;
}

推荐阅读