見出し画像

ChatGPT でデザインパターンを学ぶ - Decorator 編

ChatGPT に頼ることが増えてきていて、本当にこのままで良いのだろうかという日々を送っています。

最近、デザインパターンを学習しています。デザインパターン自体は沢山の書籍があるので、それらで学習しています。とは言え、ソースコードを自分で準備してみないと、まったく結局理解できません。ですから、拾ってきたソースコードや写経をして実行結果や経過を見ながら、血肉にしています。

デコレーターパターン

今週はデコレーターパターンです。理解はできています。使い方も分かりました。「今、目の前で組んでみろ!」と言われたらフツーにコードかけるレベル。

ただ、ユースケースが思いつきませんでした。Wikipedia 先にあるユースケースで「ふーん」とは思うものの、めっちゃ入れ子になっているコール元が驚愕すぎて、他が頭に入ってきません。

仕方ないので ChatGPT に尋ねてみました。どんなユースケースがあるのって。

デコレーターパターンは、既存のオブジェクトに新しい機能や振る舞いを追加するために使用されるデザインパターンです。以下に、Javaでデコレーターパターンを活用できるユースケースと実際の例をいくつか挙げます。
1. ファイル操作:ファイルに機能を追加するために、デコレーターパターンを使用することがあります。例えば、InputStreamやOutputStreamのサブクラスを作成し、ファイルの暗号化や圧縮などの機能を追加することができます。
2. GUIコンポーネント:GUIアプリケーションでは、デコレーターパターンを使用してコンポーネントに新しい機能や装飾を追加することがよくあります。例えば、ボーダーやスクロールバーを追加するために、JComponentクラスを拡張するデコレータクラスを作成することができます。
3. 入力検証:入力値の検証にデコレーターパターンを使用することもあります。例えば、ユーザーの入力を検証するために、Validatorクラスを基とした複数のデコレータクラスを作成し、入力値の妥当性をチェックすることができます。
4. ログ処理:ログ機能にデコレーターパターンを使用することで、ログファイルに追加情報を保存することができます。例えば、Loggerクラスを基とした複数のデコレータクラスを作成し、ログにタイムスタンプやエラーメッセージなどの情報を追加することができます。
5. ネットワーク通信:ネットワーク通信の際にもデコレーターパターンは有用です。例えば、URLConnectionクラスを継承して、リクエストやレスポンスのヘッダ情報やデータの圧縮などを追加するデコレータクラスを作成することができます。
これらはデコレーターパターンを活用できる一般的なユースケースのいくつかです。デコレーターパターンは、機能の追加や変更が頻繁に行われる場合や、クラスの継承階層を複雑化させずに機能を拡張したい場合に特に有用です。

Raycast with ChatGPT3.5

ハハーン。なるほど。1. はちょっと他のデザインパターンとかぶり気味なんだけど、インフラエンジニアとしては、4. 5. はとてもよく分かるパターンです。なるほど。cli で -v オプション付ける感じだなとか、余計なことを感じていました。と言うことで、5. のソースコードを吐いてもらいました。

interface NetworkConnection {
  sendRequest(data: string): void;
}

class BasicNetworkConnection implements NetworkConnection {
  sendRequest(data: string) {
    console.log("Sending request:", data);
  }
}

abstract class NetworkConnectionDecorator implements NetworkConnection {
  protected connection: NetworkConnection;

  constructor(connection: NetworkConnection) {
    this.connection = connection;
  }

  sendRequest(data: string) {
    this.connection.sendRequest(data);
  }
}

class LoggingDecorator extends NetworkConnectionDecorator {
  sendRequest(data: string) {
    console.log("Logging request:", data);
    super.sendRequest(data);
  }
}

class CompressionDecorator extends NetworkConnectionDecorator {
  sendRequest(data: string) {
    const compressedData = this.compressData(data);
    console.log("Compressing request:", compressedData);
    super.sendRequest(compressedData);
  }

  compressData(data: string): string {
    // データを圧縮するロジックを実装する
    return data.toUpperCase();
  }
}

// 利用例
const connection: NetworkConnection = new BasicNetworkConnection();
const connectionWithLogging: NetworkConnection = new LoggingDecorator(connection);
const connectionWithCompression: NetworkConnection = new CompressionDecorator(connection);

connection.sendRequest("Hello");
// 出力: Sending request: Hello

connectionWithLogging.sendRequest("Hello");
// 出力: Logging request: Hello
// 出力: Sending request: Hello

connectionWithCompression.sendRequest("Hello");
// 出力: Compressing request: HELLO
// 出力: Sending request: HELLO

はい、そうです。フツーに動きました。

ついでに、とても良く理解できました。データを圧縮するロジックが `toUpperCase` なのが面白すぎますけど。

もちろん重ねがけも OK です。以下を追加すれば、Compress & Logging されます。ははーん。オプション追加も余裕だと。

const connectionWithLoggingAndCompression: NetworkConnection =
  new CompressionDecorator(connectionWithLogging);

connectionWithLoggingAndCompression.sendRequest('Hello');

// 結果

Compressing request: HELLO
Logging request: HELLO
Sending request: HELLO

こんな感じで、ChatGPT(というかRaycast)のお世話になっている日々です。楽な世界だ。


ChatGPT 使わない生活もちゃんとしてて、こちらの Bookmarklet も Amazon 側の Element ID 修正にあわせて更新しました。誰も使ってないと思うけど。


この記事が参加している募集

貴方がサポートしてくれると、私が幸せ。 私が幸せになると、貴方も幸せ。 新しいガジェット・ソフトウェアのレビューに、貴方の力が必要です。