「より大きな」アプリケーションを作成していて、クラスで特定のエラーをログに記録したいとしましょう。現在、ほぼすべてのクラスが Logger にアクセスする必要があります。
1つの簡単な解決策は次のとおりです(PHPですが、それは問題ではありません):
class SomeClass {
public function someMethod() {
// stuff ...
Logger::log("something happened");
// stuff ...
}
}
このアプローチの問題は、Logger を使用するすべてのクラスがそれに依存するようになり、Logger なしで他のプロジェクトで同じクラスを単純に使用できないことです。しっかりと結合されています。また、 の実装を変更せずに、メッセージがログに記録される方法を変更することはできませんSomeClass
。
上記のアプローチの「少し」のアップグレードは次のようになります。
class SomeClass {
private $logger;
public function __construct(/* stuff */) {
$this->logger = LoggerFactory::getLogger();
}
public function someMethod() {
// stuff ...
$this->logger->log("something happened");
// stuff ...
}
}
SomeClass
は単純に に依存し、LoggerFactory
それに密結合しているため、これで問題が実際に解決されるわけではありません。これの良いところは、クラスLoggerFactory
のさまざまなインスタンスを返すことができるようになったことです。Logger
したがって、メッセージが記録される方法を変更したい場合、 の実装を変更する必要はありませんSomeClass
。
別のアプローチは、依存性注入を使用することです。
class SomeClass {
private $logger;
public function __construct(Logger $logger, /* stuff */) {
$this->logger = $logger;
}
public function someMethod() {
// stuff ...
$this->logger->log("something happened");
// stuff ...
}
}
SomeClass
現在、これは特定のクラスに結合されていません。Logger
インターフェイスを実装するクラスが必要なだけです。Logger
しかし、これに関する問題は、オブジェクトを作成するたびにインスタンスをコンストラクターに渡す必要があることです。
$object = new Position($this->logger, $x, $y);
これに関するもう 1 つの問題は、Logger が実際にはandのPosition
ようなクラスの一部ではないことです。それは単なるユーティリティです。$x
$y
そのような状況にどのように対処するのが最善ですか? この場合、カップリングと結束の間の最適な妥協点は何でしょうか?