2009-08-19 14 views
0

Ich frage mich, ob es möglich ist, die Methoden einer Klasse zu kapseln, aber dann in einer verbrauchenden Klasse verfügbar machen. Zum Beispiel (JFTR, ich weiß, dieser Code falsch ist)Encapsulating und vererben Methoden

class Consumer{ 
     public function __construct($obj){ 
      $this->obj = $obj; 
      } 

     public function doCommand(){ 
      $this->obj->command(); 
      } 
     } 

    class Consumed{ 
     //I would make the constructor private, but to save space... 
     public function __construct(){} 
     private function command(){ 
      echo "Executing command in the context of the Consumer"; 
      } 
     } 

    $consumer = new Consumer(new Consumed); 
    $consumer->doCommand(); 

    //just to reiterate, I know this throws an error 

Letztlich möchte ich Komponenten in der Lage sein zu machen, die nicht direkt vor dem Kontext einer einzelnen Controlling-Klasse verwiesen werden kann.

+0

Sie meinen etwas wie eine Freundesklasse in C++? http://en.wikipedia.org/wiki/Friend_class – VolkerK

+0

Sie können nicht beide Möglichkeiten haben, wenn Sie Funktionalität innerhalb der privaten Methode verstecken, dann kann es nicht von außen aufgerufen werden. Wenn Sie es in irgendeiner Weise verfügbar machen (indem Sie eine öffentliche Methode erstellen, die wiederum die private Methode aufruft), kann jeder Ihre private Methode aufrufen. –

+0

Der obige Kommentar ist natürlich über PHP :) Freund Klasse würde funktionieren, aber es gibt kein solches Konzept in PHP. –

Antwort

0

Sicher kann es, machen nur diese Methoden protected, nicht private und haben Consumed von Consumer zu verlängern. Ich bin mir über die Vorteile nicht sicher.

+0

, um den direkten Zugriff auf ihre Methoden zu verhindern und einen einzelnen Einstiegspunkt zu erzwingen. Ist das aus einer Designperspektive schlecht? – sunwukung

+0

Es kann sein. Ich meine, diese "konsumierte" Klasse ist grundsätzlich nicht testbar. Was wäre der Zweck einer Klasse ohne öffentliche Schnittstelle? Vielleicht ist das ein Zeichen, dass du diese Klasse nicht wirklich brauchst. Zugangsbeschränkungen garantieren nicht unbedingt ein gutes Design. Was ist das ** Problem, das Sie versuchen zu lösen? –

+0

keine wirklich - Ich studiere gerade das Thema. Ich rolle meinen eigenen MVC als Teil davon (überflüssig, ich weiß, aber eine intellektuelle Übung, um mir zu helfen) zu verarbeiten. In meiner Präsentationsschicht gibt es eine Klasse von Objekten, die vom View-Controller verwendet werden, um Teilvorlagen in einen Master einzubinden - und ich möchte verhindern, dass auf dieses Objekt direkt zugegriffen wird. Ich dachte darüber nach, nachdem ich mir die Strategie/das Befehlsmuster angeschaut hatte - in den Beispielen, die ich gesehen habe, konnten die verbrauchten Komponenten direkt abgerufen werden - und es schien, dass der einzelne Einstiegspunkt nur als ein Prinzippunkt geehrt wurde. – sunwukung

1

Sie könnte etwas ähnliches mit __call und debug_backtrace emulieren.

<?php 
class Consumer{ 
    public function __construct($obj){ 
    $this->obj = $obj; 
    } 

    public function doCommand(){ 
    $this->obj->command(); 
    } 
} 

class Consumed { 
    // classes that are aloowed to call private functions 
    private $friends = array('Consumer'); 

    public function __construct(){} 
    private function command() { 
    echo "Executing command in the context of the Consumer. \n"; 
    } 

    public function __call($name, $arguments) { 
    $dt = debug_backtrace(); 
    // [0] describes this method's frame 
    // [1] is the would-be frame of the method command() 
    // [2] is the frame of the direct caller. That's the interesting one. 
    if (isset($dt[2], $dt[2]['class']) && in_array($dt[2]['class'], $this->friends)) { 
     return call_user_func_array(array($this,$name), $arguments); 
    } 
    else { 
     die('!__call()'); 
    } 
    } 
} 

$c = new Consumed; 
$consumer = new Consumer($c); 
$consumer->doCommand(); 

echo 'and now without Consumer: '; 
$c->command(); 

druckt

Executing command in the context of the Consumer. 
and now without Consumer: !__call()