dorkahemp972157683 2017-05-05 10:31
浏览 27
已采纳

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

I am trying to understand what really defines tight coupling. I have read a number of posts on the subject but one thing still doesn't sit right with me.

I understand that classes should be injected into other classes using their interfaces rather their concrete implementations. I also understand that if a class adheres to an interface then any class which uses the injected interface can call the public functions defined in the interface and expect similar functionality.

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);
     }
}

So I think in the case where only the formatter changes, this would be defined as loosely coupled;

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

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

What I don't quite get though is when you abstract responsibilities away from each other but those classes are still closely tied to each other. Something like

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

$example = new VanOrderGenerator(new VanOrderFormatter);
$example->generate();

Yes you could pass in a different formatter to these generators, but surely more often that not some error would occur within the format function if it is expecting certain data from the generate function in the XXXOrderGenerator concrete class?

So I believe I have abstracted the responsibilities to their own classes in the last example above and although interfaces have been used i'm not sure if this is still tightly coupled or is technically loosely coupled? Or if I have missed the point entirely...

  • 写回答

2条回答 默认 最新

  • duanpei8518 2017-05-06 04:22
    关注

    Classes are said to be tightly coupled when one class has a dependency on another or relies on the internals or specifics of the other.

    In the case of the first example you gave OrderGenerator and OrderFormatter are not tightly coupled because neither one is dependent on the other: they both depend on the iFormatter. Another way of putting it is OrderFormatter knows nothing about OrderGenerator and OrderGenerator knows nothing about OrderFormatter, it just knows that the object that is passed to it implements the function 'format'. You have highlighted this when you pass either CarOrderFormatter or VanOrderFormatter to OrderGenerator without adverse result.

    In the case of the second example where CarOrderFormatter is passed to CarOrderGenerator you mentioned that surely errors would occur of you passed say VanOrderFormatter to CarOrderGenerator. If the code in CarOrderGenerator is relying on the implementation details of CarOrderFormatter then the classes are tightly coupled even though the iFormatter interface is what the CarOrderGenerator sees. This code would be confusing because CarOrderGenerator is saying with its 'contract' that it doesn't care what formatter is passed but clearly it does. It would therefore be better in terms of the clarity of the code if the CarOrderGenerator explicitly said that you could only pass a CarOrderFormatter to its constructor. The abstraction (that is, the use of the interface) is not a bad thing however and thought needs to be put into how exactly the interface should be defined. Say for example instead of having just an iFormatter interface instead you had iCarOrderFormatter and iVanOrderFormatter both of which are defined the same but the CarOrderGenerator required iCarOrderFormatter and the VanOrderGenerator required iVanOrderFormatter. The your example could become:

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

    or

    $example = new VanOrderGenerator(new PassengerVanOrderFormatter
    $example->generate();
    $example = new VanOrderGenerator(new CargoVanOrderFormatter)
    $example->generate();
    

    The key thing to realize is that the interface is introduced to create flexibility in what can be passed to the generator without it causing problems.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度