使用接口与紧耦合来提取相关功能

myo*_*yol 9 php oop decoupling

我试图了解真正定义紧耦合的原因.我已经阅读很多关于这个主题的帖子,但有一件事仍然不适合我.

我理解应该使用接口而不是具体实现将类注入其他类.我也理解,如果一个类遵循一个接口,那么任何使用注入接口的类都可以调用接口中定义的公共函数并期望类似的功能.

interface iFormatter()
{
    public function format(array $order): array
}

public class OrderFormatter implements iFormatter
{
    public function format(array $order): array
    {
        // ...

        return $formattedArray;
    }
}

public class OrderGenerator implements iGenerator
{
     private $formatter;

     public function __construct(iFormatter $formatter) 
     {
         $this->formatter = $formatter;
     }

     public function generate()
     {
          // ...

          return $this->formatter->format($order);
     }
}
Run Code Online (Sandbox Code Playgroud)

所以我认为在只有格式化器改变的情况下,这将被定义为松散耦合;

$example = new OrderGenerator(new CarOrderFormatter);
$example->generate();

$example = new OrderGenerator(new VanOrderFormatter);
$example->generate();
Run Code Online (Sandbox Code Playgroud)

我不太清楚的是,当你把责任从彼此中抽离出来时,这些课程仍然紧密相连.就像是

$example = new CarOrderGenerator(new CarOrderFormatter);
$example->generate();

$example = new VanOrderGenerator(new VanOrderFormatter);
$example->generate();
Run Code Online (Sandbox Code Playgroud)

是的,您可以将不同的格式化程序传递给这些生成器,但更确切地说,format如果期望来自具体类中的generate函数的某些数据,则函数内不会发生某些错误XXXOrderGenerator

所以我相信我已经在上面的最后一个例子中将责任抽象到他们自己的类中,虽然已经使用了接口但是我不确定它是否仍然是紧耦合的还是在技术上松散耦合?或者如果我完全错过了这一点......

Ste*_*ger 6

当一个类依赖于另一个类或依赖于另一个类的内部或细节时,类被认为是紧密耦合的.

在第一个例子的情况下,你给OrderGenerator和OrderFormatter没有紧密耦合,因为它们都不依赖于另一个:它们都依赖于iFormatter.放置它的另一种方法是OrderFormatter对OrderGenerator一无所知,而OrderGenerator对OrderFormatter一无所知,它只知道传递给它的对象实现了'format'这个函数.当您将CarOrderFormatter或VanOrderFormatter传递给OrderGenerator而没有不良结果时,您已突出显示了这一点.

对于CarOrderFormatter传递给CarOrderGenerator的第二个示例,您提到肯定会发生将VanOrderFormatter传递给CarOrderGenerator的错误.如果CarOrderGenerator中的代码依赖于CarOrderFormatter的实现细节,那么即使iFormatter接口是CarOrderGenerator看到的,这些类也是紧密耦合的.这段代码会让人感到困惑,因为CarOrderGenerator用它的"契约"说它不关心传递什么格式化程序,但显然它确实如此.因此,如果CarOrderGenerator明确表示您只能将CarOrderFormatter传递给其构造函数,那么在代码清晰度方面会更好.抽象(即,使用接口)并不是一件坏事,但需要考虑如何定义接口.比如说,而不是仅仅使用iFormatter接口,而是使用iCarOrderFormatter和iVanOrderFormatter两者定义相同,但CarOrderGenerator需要iCarOrderFormatter,VanOrderGenerator需要iVanOrderFormatter.你的例子可能变成:

$example = new CarOrderGenerator(new CarOrderFormatter
$example->generate();
$example = new CarOrderGenerator(new SportsCarOrderFormatter)
$example->generate();
Run Code Online (Sandbox Code Playgroud)

要么

$example = new VanOrderGenerator(new PassengerVanOrderFormatter
$example->generate();
$example = new VanOrderGenerator(new CargoVanOrderFormatter)
$example->generate();
Run Code Online (Sandbox Code Playgroud)

要实现的关键是引入接口以创建可以传递给生成器的灵活性,而不会导致问题.