Da nur Hunde “Apportieren” spielen können, ist dieses Beispiel eine gute oder schlechte Idee? Ich vermute, dass es aufgrund der Verwendung von instanceof eine wirklich schlechte Idee ist, aber ich bin mir nicht ganz sicher, warum.
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();
}
Ein anderes Beispiel. Da ich ständig Datenobjekte erstelle, die eine ID haben, dachte ich, ich könnte sie genauso gut alle von einer Basisklasse aus erweitern, um Codeduplizierung zu vermeiden. Auch das war schlecht, oder? Denn ein Stuhl hat keinen Namen und ein Hund keine Räder. Aber sie sind beide Datenobjekte, also ist es sehr verwirrend.
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;
}
}
Im Wesentlichen was ich denken Ich frage ist: “sollten alle Unterklassen die gleiche Schnittstelle haben oder können sie unterschiedliche haben?”
In diesem Zusammenhang ist es sinnvoll, darüber zu sprechen Schnittstellen.
interface Talkative {
public function speak();
}
class Dog extends Animal implements Talkative {
public function speak() {
return "Woof, woof!";
}
}
Jedes Tier oder Mensch (oder Alien), das die Talkative-Schnittstelle implementiert, kann in einem Kontext verwendet werden, in dem gesprächige Wesen benötigt werden:
protected function makeItSpeak(Talkative $being) {
echo $being->speak();
}
Dies ist ein richtig verwendetes polymorphes Verfahren. Es ist dir egal was Sie beschäftigen sich so lange wie möglich speak()
.
Wenn Dog
s können auch Apportieren spielen, das ist toll für sie. Wenn Sie das verallgemeinern wollen, denken Sie auch an eine Schnittstelle. Vielleicht bekommen Sie eines Tages eine gut ausgebildete Katze, die auch Apportieren spielen kann.
class Cog extends Cat implements Playfulness {
public function playFetch() { ... }
}
Der wichtige Punkt hier ist, dass wenn Sie Anruf playFetch()
auf etwas, weil du mit diesem Tier Apportieren spielen willst. Du rufst nicht an playFetch
weil, naja… du kannst, aber weil du in diesem Moment Apportieren spielen willst. Wenn Sie nicht Apportieren spielen wollen, dann rufen Sie es nicht an. Wenn Sie in einer bestimmten Situation Apportieren spielen müssen, brauchen Sie etwas, das Apportieren spielen kann. Dies stellen Sie durch Schnittstellendeklarationen sicher.
Sie können dasselbe mit Klassenvererbung erreichen, es ist nur weniger flexibel. In einigen Situationen, in denen starre Hierarchien bestehen, ist es jedoch durchaus nützlich:
abstract class Animal { }
abstract class Pet extends Animal { }
class Dog extends Pet {
public function playFetch() { ... }
}
class GermanShepherd extends Dog {
public function beAwesome() { ... }
}
Dann benötigen Sie in einem bestimmten Kontext möglicherweise nicht irgendein Objekt das kann was (interface), aber du suchst gezielt nach einem GermanShepherd
weil nur es großartig sein kann:
protected function awesomeness(GermanShepherd $dog) {
$dog->beAwesome();
}
Vielleicht machen Sie später eine neue Art von GermanShepherd
s, die sind auch toll, aber extend
das GermanShepherd
Klasse. Sie werden immer noch mit dem arbeiten awesomeness
funktionieren, genau wie bei Schnittstellen.
Was Sie auf keinen Fall tun sollten, ist, einen Haufen zufälliger Dinge durchzugehen, zu überprüfen, was sie sind, und sie ihr eigenes Ding machen zu lassen. Das ist einfach in keinem Zusammenhang sehr sinnvoll.
Ein weiteres Beispiel für Polymorphismus in 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);
?>
Fast genauso wie du, Krishnadas, Brad. Dieser Artikel hat mir sehr geholfen zu verstehen, wie man mit Polymorphismus in PHP umgeht
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);
Ich bin mir ziemlich sicher, dass dies hier schon einmal gefragt wurde, aber die kurze Antwort lautet, dass es in Ordnung ist, wenn Unterklassen eine andere Schnittstelle haben.
– NullUserException
17. Dezember 2011 um 4:51 Uhr
Ich bin mir ziemlich sicher, dass das erste Beispiel aufgrund der Verwendung von instanceof für bedingte Logik nicht richtig ist. Besteht nicht der ganze Sinn des Polymorphismus darin, dies nicht zu tun?
– Dan
17. Dezember 2011 um 4:55 Uhr
Warum sollten Sie alle Tiere dazu bringen, etwas zu tun (sprechen), außer einer Art (Hund)? Klingt so, als ob die fehlerhafte Logik in der Schleife liegt, nicht die Klassendefinitionen.
– NullUserException
17. Dezember 2011 um 4:58 Uhr
Alle sprechen, auch der Hund. Aber nur der Hund kann Apportieren spielen. So oder so denke ich, dass ich hier etwas Hilfreiches gefunden haben könnte: stackoverflow.com/questions/6119087/…
– Dan
17. Dezember 2011 um 5:03 Uhr
Wenn zwei verschiedene Objekte dasselbe auf unterschiedliche Weise tun können, ist das Polymorphismus. Wenn ein Objekt kann zusätzlich etwas anderes tun, na ja, so sei es. Das ist dann einfach kein polymorphes Verhalten, da es ein für das Objekt einzigartiges Verhalten ist. Sie würden dieses spezifische Verhalten dann einfach nicht als polymorph behandeln.
– verzeihen
♦
17. Dezember 2011 um 5:04 Uhr