私の質問は、OOP の使用方法をよりよく理解するために作成した 3 つのサンプル クラスに当てはまります。
class Book {
//not using getters/setters to save some space
public $name;
public $numreads;
}
class BookFactory {
private $db;
public function __construct(Database $db) {
$this->db = $db;
}
public function getBook($id) {
$book = new Book();
$book->name = $db->query("SELECT name FROM books...");
$booknumreads = new BookNumRead($this->db, $book);
$book->numreads = $booknumreads->getFromLocal() + $booknumreads->getFromAnotherSource();
return $book;
}
}
class BookNumRead {
private $db;
private $book;
public function __construct(Database $db, Book $book) {
$this->db = $db;
$this->book = $book;
}
public function getFromLocal()
{
return $this->db->query("SELECT COUNT ... WHERE name = $book->name");
}
public function getFromAnotherSource()
{
return API::getNumReadsOfABook($book->name);
}
//or just stick with this method in this class
public function getNumReadsOfBook($name)
{
return (
$this->db->query("SELECT COUNT ... WHERE name = $name")
+
API::getNumReadsOfABook($name)
);
}
}
//get number of reads of a book
$db = new Database();
$bookfactory = new BookFactory($db);
$book = $bookfactory->getBook(123);
echo $book->getNumReads();
まず第一に、これは良い OOP アプローチですか?
これらのクラスはかなり異なります。ドメイン対値オブジェクト? たとえば、アプリケーションで必要な数の Book オブジェクトを使用できます。ただし、BookFactory はアプリケーションのサービスのようなものです。アプリケーションに必要なのは 1 つだけですが、アプリケーションの他の多くの場所からこのクラスが必要になる場合があります。ServiceLocator/ServiceContainer にオブジェクトとして配置する必要がありますか?
BookNumRead クラスを ServiceLocator/ServiceContainer に配置して、Book オブジェクトを挿入せずに getNumReadsOfBook() メソッドで使用することもできますが、それは手続き型プログラミングのように感じますか? または、上記の例のように BookFactory::getBook() によって開始されますが、データベース (1 つの BookFactory が注入されたもの) と Book の両方をデータベースに渡す必要があります。たとえば、ロガーなどの他の「サービス」クラスが必要になる場合があります。ここでのベストプラクティスは何ですか?