1

このプロジェクトには目標があります。それは、インターフェース中心の設計を使用することです。基本的には公開純粋関数のみのクラスを宣言し、それを実クラスに継承させます。

ここで 1 つの質問があります。ユーティリティ関数を再利用するにはどうすればよいでしょうか。

次に例を示します。

class InterF1 {
  public:
    int f1() = 0;
    int g1() = 0;   
}; 

class InterF2 {
  public:
    int f2() = 0;
}; 

class C1: public InterF1 {
  public:
    int f1();
    int g1();
};


class C2: public InterF1, InterF2 {
  public:
    int f1();
    int g1();
    int f2();
};

C1::f1() と C2::f1() を実装していますが、これら 2 つの関数の間でコードの重複が見られます。重複を削除するにはどうすればよいですか?

ここに私の考えがあります:

1) 次のように protected をインターフェイス クラスに追加できます。

class InterF1 {
  public:
    int f1() = 0;
    int g1() = 0;   
  protected:
    int util();
    int convenient_var_calculated_by_util;
}; 

上記の設計では、C1::f1() と C2::f2() の両方が util() を呼び出すことができます。

2) 新しいインターフェースを抽象化できます:

class UtilI {
    public:
      int util(int in_var) = 0;
};

この設計では、InterF1、C1、および C2 が次のように変更されます。

class InterF1 {
  public:
    int f1(UtilI u) = 0;
    int g1() = 0;   
}; 

class C1: public InterF1 {
  public:
    int f1(UtilI u);
    int g1();
};


class C2: public InterF1, InterF2 {
  public:
    int f1(UtilI u);
    int g1();
    int f2();
};

C1::f1() と C2::f1() は両方とも UtilI API を呼び出します。

解決策 2 は、「インターフェイス中心」の目標により適しているように見え、見た目も良くなります。しかし、1 つの懸念があります。InterF1 と InterF2 自体は、実装の詳細である UtilI よりも高いレベルの抽象化である必要があります。2 つのレベルを混在させていますか? つまり、後で実装が変更された場合、f1() と f2() の署名を再度更新するために戻ってくる必要がありますが、これは正しくないように思えます。

解決策 1 は便利そうに見えますが、私には「純粋」ではないように見えます。

4

2 に答える 2

3

通常、共通の実装を基本クラスに配置する必要があると思いますが、基本クラスが純粋に仮想であるという要件があります。代わりに、次のいずれかをお勧めします。

  1. 中間実装クラスを作成する

    InterF2実装したいすべてのクラスがも実装したい場合、このアプローチは問題ありませんInterF1

    アプローチは実装することです

    class InterF1Impl: public InterF1 {
      public:
        int f1();
        int g1();
    }
    

    次に、共通のandメソッドを実装するC1andのC2両方を派生させることができます。InterF1Implf1()g1()

    C3 : public InterF2ただし、の実装を共有しf2()たいC2が を実装したくない別のクラス がある場合、このアプローチはうまく拡張されませんInterF1

    代替の(そしてより良い)アプローチは

  2. 構成を使用して実装クラスを含めます

    このアプローチでは、上記のように実装しますが、派生するInterF1Impl: public InterF1代わりに、クラスの一部になります。 C1: public InterF1ImplInterF1ImplC1

    class C1: public InterF1 {
      private:
        InterF1Impl * f1impl;
      public:
        int f1();
        int g1();
    }
    

    C1::f1()およびC1::g1()メソッドは、 から対応するメソッドを呼び出すだけですf1impl

    このように、 の共通の実装が必要な場合は、f2()も実装でき、同様の方法で実装できます。InterF2: public InterF2C2

    class C2: public InterF1, InterF2 {
      private:
        InterF1Impl * f1impl;
        InterF2Impl * f2impl;
      public:
        int f1(); /* calls f1impl->f1() */
        int g1(); /* calls f1impl->g1() */
        int f2(); /* calls f2impl->f2() */
    }
    

    また、別のクラスは、後でそのようなクラスが必要になった場合に、実装InterF2せずに の実装を使用することもできます。InterF1

于 2012-04-10T03:11:51.123 に答える
0

あなたの2番目のソリューションは1番目のソリューションよりも優れていますが、私は別の方法で行います.

まず第一に、コードの再利用は、オブジェクト間の継承または構成関係のいずれかによって実現できます。この場合、以下で説明するように、合成アプローチの方が理にかなっています。

util()あなたのクラスのユーザーは、おそらくメソッドの実装やその存在さえ気にしません。そのため、UtilIインターフェイスを用意してパブリック API の一部にする必要はないようです。ユーティリティ ロジックはインターフェイスではなく実装の一部であるため、このクラスは C1 および C2 クラスの実装でのみ使用する必要があります。そのようにすれば、UtilIインターフェースは必要ない可能性が高く、具象クラスだけで置き換えることができますUtil。おそらく、このクラスをステートレスにして、静的メソッドのみを持つようにすることができます。そうでない場合は、シングルトンであるか、クラスが独自のインスタンスを作成できます (必要なものに応じて)。

インターフェース中心の設計は良い目標ですが、公開すべきものだけを公開することが重要です。これは、API を設計する上で不可欠な部分であり、完全最小限でなければなりません。

于 2012-04-10T02:58:34.930 に答える