1

次のクラス階層を検討してください。

Abstract class Printer{
    public print(){
        //code to handle printing
    }
}

class LaserPrinter extends Printer{
    private $file;
    public setFile($file){
        $this->file = $file; 
    }
}

class InkJetPrinter extends Printer{
    private $document;
    public setDocument($document){
        $this->document= $document; 
    }
}

class ClientClass{
    private $filesToPrint=array();
    public __construct(InkJetPrinter $inkJetPrinter, LaserPrinter $laserPrinter){   //I was hoping to apply Dependency Inversion here by defining both inputs as type Printer instead
         //constructor stuff    
    }

    public function startPrinting(){
         //some logic to extract the $files and $documents from $this->filesToPrint
         //...
         $this->inkJetPrinter->setDocument($document);//<---Things got messy here
         $this->laserPrinter->setFile($file);//<---and here too
         //...
    }
}

にはメソッドがないため、クラスLaserPrinterを親に置き換えることはできません。 それは、彼のヒエラルキーがリスコフの代用原理を破っているということですか? サブクラスが独自のパブリック メソッドを持つことは許可されていませんか?PrinterPrintersetFile

4

2 に答える 2

1

逆に言えば、Liskov Substitution Principle を満たすには、親クラスが使用されている場所ならどこでも子クラスを使用できる必要があります。あなたの例では、タイプのオブジェクトが期待されるLaserPrinterオブジェクトまたはオブジェクトを使用できるはずです。したがって、どの独自の public メソッド サブクラスが持っているかは問題ではありません。InkJetPrinterPrinter

これにより、Open/Closed Principle を満たす方法が開かれます。新しいプリンターを作成できるため、モジュールを変更せずに (プリンターを使用する) モジュールの動作を拡張できます。

更新: 現在のコードには LSP について何もありません。PrinterNetwork は、ファイルの印刷に子クラスを使用しています。代わりに、親クラスを使用する必要があります。PHPはわかりませんが、次のようになります。

class PrinterNetwork{
    private $filesToPrint=array();
    public __construct(Printer $printer){
         //constructor stuff    
    }

    public function startPrinting(){
         //foreach file in $this->filesToPrint
         $this->printer->print($file);
         //...
    }
}

InkJetPrinter または LaserPrinter でネットワークを初期化できます。コードは、プリンターの種類に依存しないようにする必要があります。どちらも問題なく親を代用する必要があります。

于 2012-10-17T20:56:16.490 に答える
1

まず第一に、そのコードには継承があると思いますが、LaserPrinter または InkJetPrinter が Printer から継承されていることを示唆するものは何も見当たりません。

いいえ、それはリスコフの原則を破るものではありません。なぜなら、サブクラスは、プリンターとして使用されるときに適切に動作する必要があるからです。

あなたの質問を引き起こしているかもしれないビットは、クラスも Depedency Inversion を使用する必要があるため、完全に構築された LaserPrinter を Printer を使用するものに渡す必要があるということです。そこにある例では、LaserPrinter が作成されるとファイルを変更できますか?

ファイルを変更する必要がない場合は、おそらくそれを LaserPrinter のコンストラクターに渡します。ファイルが変更される可能性がある場合は、LaserPrinter 内でファイル名を作成するか、ファイル名を作成してから LaserPrinter にクラスを挿入する新しいクラスを作成します。

Open/ClosedおよびDependency Inversionの原則について読みたいと思うかもしれません。それらはあなたの質問に非常に密接に関連していると思います。


編集

コードをもう一度見てみると、何かおかしいと思います。Printer.print()何を印刷するかを説明するパラメータを受け取る必要があります。インスタンス変数から出力する必要があるものを or で参照するのは間違っているように見えますLaserPrinterInkJetPrinter

たとえば、「プリンター、ここにドキュメントがあります... 今すぐ印刷します」とは言いません。

プリンターのようなものです。完全に構成して実行しているので、このドキュメントを印刷してください

印刷したいものを表す (ドキュメントとファイルをカプセル化する) オブジェクトが既にあるようです。そのオブジェクトを渡して、のようなものを持つことができますprint(jobDetail)

于 2012-10-17T21:02:34.553 に答える