Подтвердить что ты не робот

Общий полиморфизм с примерами PHP

Как только собаки могут играть "извлечения", является ли этот пример хорошей или плохой идеей? Я подозреваю, что это действительно плохая идея из-за использования instanceof, но я не совсем уверен, почему.

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;
    }
}

По сути, я думаю, что я спрашиваю: "должны ли все подклассы иметь один и тот же интерфейс или могут иметь разные?"

4b9b3361

Ответ 1

В этом контексте полезно говорить о интерфейсах.

interface Talkative {
    public function speak();
}

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

Любое животное или человек (или иностранец), реализующее интерфейс Talkative, может использоваться в контексте, в котором нужны болтливые существа:

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

Это правильно используемый полиморфный метод. Вам все равно, что вы имеете в виду, если это возможно speak().

Если Dog также может воспроизводить выборку, это здорово для них. Если вы хотите обобщить это, подумайте об этом и с точки зрения интерфейса. Возможно, однажды вы получите высококвалифицированного кота, который также может играть в выборку.

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

Важным моментом здесь является то, что когда вы вызываете 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();
}

Возможно, по дороге вы создадите новую породу GermanShepherd, которая также удивительна, но extend класс GermanShepherd. Они все равно будут работать с функцией awesomeness, как с интерфейсами.

То, что вы, конечно же, не должны делать, - это перебрать кучу случайных вещей, проверить, что они собой представляют, и заставить их делать свое дело. Это просто не очень разумно в любом контексте.

Ответ 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);
?>

Ответ 3

Почти так же, как вы, Кришнадас, Брэд. Эта статья очень помогла мне понять, как обращаться с полиморфизмом в PHP

http://code.tutsplus.com/tutorials/understanding-and-applying-polymorphism-in-php--net-14362

interface shape_drawer{
    public function draw(Shape $obj);
}

class circle implements shape_drawer{
    public function draw(Shape $obj){
        echo "Drawing Circle, Area: {$obj->area} <br>";
    }
}

class square implements shape_drawer{
    public function draw(Shape $obj){
        echo "Drawing Square, Area: {$obj->area} <br>";
    }
}

class triangle implements shape_drawer{
    public function draw(Shape $obj){
        echo "Drawing Triangle, Area: {$obj->area} <br>";
    }    
}

class shape_factory{
    public static function getShape(){

        $shape = $_REQUEST['shape'];

        if(class_exists($shape)) {
            return new $shape();
        }
        throw new Exception('Unsupported format');
    }
}

class Shape{

    public function __construct($area){
        $this->area = $area;
    }
    public function draw(shape_drawer $obj) {
        return $obj->draw($this);
    }
}


$shape = new Shape(50);
try {
    $drawer = shape_factory::getShape();
}
catch (Exception $e) {
    $drawer = new circle();
}

echo $shape->draw($drawer);