一般多态性与 PHP 示例

2022-08-30 15:06:30

由于只有狗可以玩“抓取”,这个例子是好主意还是坏主意?我怀疑由于使用实例,这是一个非常糟糕的主意,但我不完全确定为什么。

class Animal {
    var $name;
    function __construct($name) {
        $this->name = $name;
    }
}

class Dog extends Animal {
    function speak() {
        return "Woof, woof!";
    }

    function playFetch() {
        return 'getting the stick';
    }
}

class Cat extends Animal {
    function speak() {
        return "Meow...";
    }
}

$animals = array(new Dog('Skip'), new Cat('Snowball'));

foreach($animals as $animal) {
    print $animal->name . " says: " . $animal->speak() . '<br>';
    if ($animal instanceof Dog) echo $animal->playFetch();
}

另一个例子。由于我不断创建具有 ID 的数据对象,因此我想我不妨将它们从基类全部扩展,以避免代码重复。再说一遍,这很糟糕吧?因为椅子没有名字,狗也没有轮子。但它们都是数据对象,所以非常令人困惑。

class Data_Object {
    protected $_id;

    function setId($id) {
        $this->_id = $id;
    }

    function getId() {
        return $this->_id;
    }
}

class Dog extends Data_Object {
    protected $_name;
    function setName($name) {
        $this->_name = 
    }

    function getName() {
        return $this->_name;
    }
}

class Chair extends Data_Object {
    protected $_numberOfWheels;
    function setNumberOfWheels($number) {
        $this->_numberOfWheels = $number;
    }

    function getNumberOfWheels() {
        return $this->_numberOfWheels;
    }
}

从本质上讲,我认为我要问的是:“所有子类都应该具有相同的接口,还是可以有不同的接口?


答案 1

在这种情况下,讨论接口是很有用

interface Talkative {
    public function speak();
}

class Dog extends Animal implements Talkative {
    public function speak() {
        return "Woof, woof!";
    }
}

任何实现Talkative界面的动物或人类(或外星人)都可以在需要Talkative生物的上下文中使用:

protected function makeItSpeak(Talkative $being) {
    echo $being->speak();
}

这是一种正确使用的多态方法。只要可以,您就不在乎您正在处理什么speak()

如果 s 也可以玩 fetch,那对他们来说很棒。如果你想概括这一点,也要从接口的角度来考虑它。也许有一天你会得到一只训练有素的猫,它也可以玩抓取。Dog

class Cog extends Cat implements Playfulness {
    public function playFetch() { ... }
}

这里重要的一点是,当你调用某物时,这是因为你想和那只动物一起玩抓取。你不打电话是因为,嗯...你可以,但因为你想在这一刻玩抓取。如果你不想玩抓取,那么你就不叫它。如果你需要在某种情况下玩 fetch,那么你需要一些可以玩 fetch 的东西。您可以通过接口声明来确保这一点。playFetch()playFetch

您可以使用类继承实现相同的目标,只是灵活性较低。在某些情况下,存在严格的层次结构,尽管它非常有用:

abstract class Animal { }

abstract class Pet extends Animal { }

class Dog extends Pet {
    public function playFetch() { ... }
}

class GermanShepherd extends Dog {
    public function beAwesome() { ... }
}

然后,在某些特定的上下文中,您可能不需要任何可以执行某些操作(接口)的对象,但是您专门寻找一个,因为只有它可以很棒:GermanShepherd

protected function awesomeness(GermanShepherd $dog) {
    $dog->beAwesome();
}

也许在这条路上,你会制造出一种同样令人敬畏的新品种,但是这个类。它们仍然可以使用该函数,就像使用接口一样。GermanShepherdextendGermanShepherdawesomeness

你当然不应该做的是循环一堆随机的东西,检查它们是什么,让它们做自己的事情。这在任何情况下都不是很明智。


答案 2

PHP 中多态性的另一个示例

    <?php
interface Shape {
   public function getArea();
}

class Square implements Shape {
   private $width;
   private $height;

   public function __construct($width, $height) {
      $this->width = $width;
      $this->height = $height;
   }

   public function getArea(){
      return $this->width * $this->height;
   }
}

class Circle implements Shape {
   private $radius;

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

   public function getArea(){

      return 3.14 * $this->radius * $this->radius;
   }
}

function calculateArea(Shape $shape) {
   return $shape->getArea();
}

$square = new Square(5, 5);
$circle = new Circle(7);

echo calculateArea($square), "<br/>";
echo calculateArea($circle);
?>

推荐