web-dev-qa-db-ja.com

基本クラスが新しいメソッドのオーバーロードをサポートする場合のデザインパターン

基本クラス(私が所有していない基本lib内)は、そのコードをアップグレードし、追加のユースケースをサポートする新しいメソッドを追加しました。

これは、基本クラスの既存のメソッドシグネチャです。

public void Alert(string someAlertString);

新しいリリースでは、基本クラスはAlertObjectのリストをサポートしています(ある時点で、基本クラスは文字列アラートを非推奨にする可能性があります)。

public void Alert(List<Alert> alertObj);

Libの基本クラスは次のようになります。

public BaseClass {
   public void Alert(string message) {
     //Print msg on the UI.
   }

   public void Alert(List<Alert> alerts) {   <-- New Addition.
     // Loop through each alert and show the list of messages.
   }

   // Other methods.
}

コードの私の側では、次のように、複数のサブクラスの複数の場所にアラートがあります(> 500アラート)。

public SubClass: BaseClass {

    public void Execute(){
       // Execute some logic
       Alert("This is a warning message."); <-- Call base calls alert
    }
 }

AlertObjectを使用するようにこれらすべてのアラートステートメントを更新します(新しいアラートにのみカテゴリを追加します。古いアラートはデフォルトのカテゴリを引き続き使用できます)。

public class Alert {
   public string message {get;set;}
   public string category {get;set;}
}

これを行う1つの方法は、既存の文字列を受け取り、AlertObjectのリストを返すヘルパークラスを定義することです。

public static class AlertHelper {
   public static List<Alert> getNewAlert(string msg, string category="Not Defined") {
      Alert a = new Alert();
      a.message = msg;
      a.category = category;
      return new List<Alert>() { a };
   }
}

次に、アラートのすべてのインスタンスを次のように置き換えます。

base.Alert(AlertHelper.getNewAlert("This is a warning message."))

ここで私が目にする1つの問題は、Alertクラス(別のlib内)がより詳細なアラートをサポートするプロパティを追加し続けるので、ヘルパークラスを更新し続ける必要があり、ヘルパークラスを呼び出すすべての場所を潜在的に更新する必要があることです。

これを設計するより良い方法があるかどうか私は思っていました。

1
user9969157

外部ライブラリの最高の機能の1つは、変化しない署名です。ライブラリでよく使用される機能のシグネチャを変更し続けると、コンシューマに組み込むのが簡単になります。

私には、追加機能のように聞こえますが、ライブラリクラスにあるべきです。既存のメソッドの署名を変更することなく。このようなもの:

public class AlertsLibrary 
{
    // Base method remains the same, though with category added. 
    // The default value ensures that old code does not need change.
    public void Alert(string alertMessage, string category = "Not defined") 
    {
        ...
    }

    // Overload to allow a list of messages, but still handled with the base method.
    public void Alert(IEnumerable<string> alertMessages)
    {
        foreach(var msg in alertMessages) 
        {
            Alert(msg);
        }
    }

    // You can even overload with an alert object if you'd like (must be in the library as well)
    public void(Alert alert) 
    {
        Alert(alert.Message, alert.Category);
    }
}

次に、IEnumerable<Alert>を受け取り、基本メソッドを何度も呼び出すメソッドを作成することもできます。これは、古いコードを壊すことなく、あなたが説明するすべての機能を許可します。

まず、ヘルパークラスは必要ありません。a=Alert.of("alert msg")は簡潔で、Alertに関連するすべてのものをAlertクラスに保持します。
2番目に、サードパーティのlibを変更せずに、このような動作を実装するために extension methods を使用できます。
このメソッドの実装を変更して、Alertの新しいプロパティに準拠させることができます。パラメータとしてStringを受け取り、同じAlertを返すため、Alert.of()を呼び出す各行を変更する必要はありません。

より細かく制御するもう1つの方法は、独自のAlertAdaptor extends Alertを作成して使用することです。サードパーティのlibの変更から呼び出し側を保護するために、多くのことをカプセル化できます。
より防御的な方法はAlertAdaptor extends Alert implements IAlertで、IAlertにはAlertから必要なメソッドが含まれます。その場合、Alertのプロパティとフィールドは使用せず、独自のインターフェースのメソッドを使用するため、Alert.messageAlert.shortMsgになったときに必要なのは、AlertAdaptorに1行を書き込むことだけです。
しかし、防御には労力がかかります。ライブラリがIAlertに役立つ機能を導入するたびに、Alertを変更する必要があります。

0
ADS

古い方法が廃止されると思われる理由がわかりません。また、既存の呼び出しを置き換える理由はありません。

新しい呼び出しによってコードが簡略化されるか、UIが改善される状況がある場合は、それを使用してください。古いインターフェイスが機能する場合は、そのまま使用してください。

500件の呼び出しを変更し、コードレビューで変更を拒否することは、私の考えではありません。

0
gnasher729