💋

Dartでみる疎結合と密結合について

2023/12/04に公開

Overview

最近、勉強会で疎結合密結合という言葉を聞くようになりました。知識がないもので、技術について解説されたサイトや書籍を見て、情報を集めて今回はDartで表現してみました。

疎結合(Loose Coupling):

クラス間の依存性が低い状態を指します。
一つのクラスが変更されても他のクラスに影響を与えにくいです。
再利用性が高く、テストや保守が容易です。
抽象クラスやインターフェースを使用して達成されます。
密結合(Tight Coupling):

クラス間の依存性が高い状態を指します。
一つのクラスが変更されると他のクラスも影響を受けやすいです。
再利用性が低く、テストや保守が困難になります。
他のクラスの内部構造や実装詳細に依存しています。
これらの概念は、ソフトウェア設計の重要な原則の一部であり、ソフトウェアの品質と保守性に大きな影響を与えます。

summary

DartPadで実行できるように、以下に密結合と疎結合のサンプルコードを作成します。

🔧密結合

まず、密結合の例です。ここでは、LoggerクラスがConsoleLoggerクラスに直接依存しています。

class ConsoleLogger {
  void log(String message) {
    print('Console Logger: $message');
  }
}

class Logger {
  final ConsoleLogger consoleLogger = ConsoleLogger();

  void log(String message) {
    consoleLogger.log(message);
  }
}

void main() {
  Logger logger = Logger();
  logger.log('これは、密結合です!');
}

実行結果

🔧疎結合

次に、疎結合の例です。ここでは、LoggerクラスはLoggerInterfaceという抽象クラスに依存しています。具体的な実装はConsoleLoggerクラスにありますが、Loggerクラスはそれに直接依存していません。

abstract class LoggerInterface {
  void log(String message);
}

class Logger {
  final LoggerInterface loggerInterface;

  Logger(this.loggerInterface);

  void log(String message) {
    loggerInterface.log(message);
  }
}

class ConsoleLogger implements LoggerInterface {
  
  void log(String message) {
    print('Console Logger: $message');
  }
}

void main() {
  Logger logger = Logger(ConsoleLogger());
  logger.log('これは疎結合です!');
}

実行結果

thoughts

一般的には、疎結合の設計が推奨されます。これは、疎結合の設計がソフトウェアの再利用性、拡張性、保守性を向上させるからです。しかし、密結合の設計も一部の状況や特定の小規模なプロジェクトでは有用であることがあります。そのため、どちらの設計を採用するかは、プロジェクトの要件、規模、期間などによります。

普段Dartでコードを書くときは、ここまで意識していなかったりしました。ソフトウェアの開発手法を最近学んでいるのですが、Flutterで開発といえば、riverpod + Freezed + go_router使ってればいいだろうという現場しか見てないので、抽象クラスに機能がないロジックを定義して、継承して機能を実装したり、APIやDBを操作するロジックを実行するクラス、入力に応じて、画面に動きをつけたりエラー処理の状態を扱うクラス、他にも色々分けるコードを見て、保守やテストがしやすい、使いまわせる再利用性の高いコードを書くことの大事さを学びました。

と言いながらも、いまだに良い感じのコードが書けてないのが悩みですね。UIStateだけは完全に分離して、ViewとProviderに分けたりしたいです。

Discussion