Как только Собаки могут играть «извлечения», является ли этот пример хорошей или плохой идеей? Я подозреваю, что это очень плохая идея из-за использования экземпляра, но я не совсем понимаю, почему.
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; } }
По сути, я думаю, что я спрашиваю: «Должны ли все подклассы иметь один и тот же интерфейс или у них могут быть разные?»
В этом контексте полезно говорить о интерфейсах .
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
s также может играть в выборку, это здорово для них. Если вы хотите обобщить это, подумайте об этом и с точки зрения интерфейса. Возможно, в один прекрасный день вы получите высококвалифицированного кота, который также сможет играть в выборку.
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
новую породу GermanShepherd
s, которые также удивительны, но extend
класс GermanShepherd
. Они по-прежнему будут работать с функцией awesomeness
, как с интерфейсами.
То, что вы, конечно же, не должны делать, – это пройти через кучу случайных вещей, проверить, что они собой представляют, и заставить их делать свое дело. Это просто не очень разумно в любом контексте.
Другой пример полиморфизма в 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); ?>
Почти так же, как вы, Кришнадас, Брэд. Эта статья очень помогла мне понять, как обращаться с полиморфизмом в 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);