2

この例を考えてみましょう

インターフェイス

interface IBusinessRules
{
    string Perform();
}

相続人

class Client1BusinessRules: IBusinessRules
{
    public string Perform()
    {
        return "Business rule for Client 1 Performed";
    }
}

class Client2BusinessRules: IBusinessRules
{
    public string Perform()
    {
        return "Business rule for Client 2 Performed";
    }
}

class Client3BusinessRules: IBusinessRules
{
    public string Perform()
    {
        return "Business rule for Client 3 Performed";
    }
}

ファクトリークラス

class BusinessRulesFactory
{
    public IBusinessRules GetObject(int clientIdentityCode)
    {
        IBusinessRules objbase = null;
        switch (clientIdentityCode)
        {
            case 1:
                objbase = new Client1BusinessRules();
                break;
            case 2:
                objbase = new Client2BusinessRules();
                break;
            case 3:
                objbase = new Client3BusinessRules();
                break;
            default:
                throw new Exception("Unknown Object");
        }
        return objbase;
    }
}

使用例:

class Program
{
    static void Main(string[] args)
    {
        BusinessRulesFactory objfactory = new BusinessRulesFactory ();
        IBusinessRulesFactory objBase = objfactory.GetObject(2);
        Console.WriteLine(objBase.Perform());

        objBase = objfactory.GetObject(3);
        Console.WriteLine(objBase.Perform());
        Console.Read();
    }
}

私の質問は、 特別なシナリオで使用するだけなので、ALgorithm1 クラスに別のメソッドを追加するが、インターフェイスには追加しないということです。

class Client1BusinessRules: IBusinessRules
{
    public string Perform()
    {
        return "Client1 Business rules is Performed";
    }


    public string Calculate()
    {
        return "Additional functionality for CLient1";
    }
}

このようなUIでそれをどのように呼び出すと思いますか

 objBase = objfactory.GetObject(1);
 Console.WriteLine(objBase.Calculate());

他の解決策はありますか?前もって感謝します

編集:現在のプロジェクトデザインに似るように書き直しました

4

6 に答える 6

3

次の目的でファクトリクラスを使用していると思います。

  • ビジネスルールの選択とプロビジョニングにつながるパラメータを受け入れる標準のファサードを持っている
  • ビジネスルールのプロビジョニングをカプセル化する
  • の実際の実装からユーザーを切り離しますIBusinessRules

したがって、私は新しいインターフェースを導入することによってあなたの問題を解決します

interface IComputableRules : IBusinessRules
{
    string Calculate();
}

インターフェイスベースの設計に従っている限り、実際のインスタンスをとは異なるインターフェイスにキャストしても問題はありませんIBusinessRules

IBusinessRules businessRule = objFactory.GetObject(...some input...)
...
// check if the computable service is supported and print the result
IComputableRules computable = businessRule as IComputableRules;
if (computable)
{
     Console.WriteLine(computable.Calculate());
}

ここでは、ビジネスルールクラスを、いくつかの基本的なサービスに加えて、ビジネスルールの性質に応じたオプションの追加サービスを保証するサービスプロバイダーと考えることができます。

注:BusinessRulesFactoryをジェネリッククラスに変換することで、特定のサービスの表示をファクトリコントラクトの一部にし、返されたビジネスルールの実装が特定の(それ以外の場合はオプションの)サービスをサポートするようにすることができます。

class BusinessRulesFactory<TService> where TService : IBusinessRules
{
     public TService GetObject(int clientIdentityCode)
     {
         // ... choose business rule in respect to both clientIdentityCode and TService
     }
}

特定の追加サービスを利用する必要がない場合はIBusinessRules、実際のタイプパラメータとして使用するだけです。

于 2010-09-12T08:32:39.557 に答える
3

ファクトリ パターンの要点は、コントラクトの適切な実装を返すことです。これにより、コントラクトをインスタンス化する方法を消費者が気にせず、単にそのメソッドを呼び出すことができます。いつでも実際の型をテストし、それにキャストしてメソッドを呼び出すことができますが、それは非常に悪い設計であり、お勧めしません。消費者は実際の型について何も知らないはずです。設計を再考する必要があります。

于 2010-09-12T08:04:12.277 に答える
3

現在のアーキテクチャに固執したい場合は、新しいインターフェイス宣言を導入できます

interface ICalculationRules  
{  
    string Calculate();  
}

Client1BusinessRules次に、インターフェイス宣言を追加して変更します。

class Client1BusinessRules: IBusinessRules, ICalculationRules
{
     // everything remains the same  
}

呼び出しコードを次のように変更します。

var objBase = objfactory.GetObject(1);  
Console.WriteLine(objBase.Calculate());    
var calcBase = obj as ICalculationRules;     
if (calcBase != null) calculable.Calculate();     

保守の意味: 新しいインターフェースを導入するたびに、すべての呼び出しコードに手を加える必要があります。このコードがUIコードに配置されていると投稿したので、これはかなり混乱する可能性があります.

導入する各インターフェースは、クラスに追加された動作を意味します。さまざまな動作が広範囲に及ぶ場合、上記のソリューションは正しくないと感じます。なぜなら、常にas操作と条件付き実行メソッドを使用する必要があるからです。古典的なデザインパターンに固執したい場合は、この動作の変動性をデコレーターパターンまたはストラテジーパターンで打ち消すことができます。ファクトリーパターンとスムーズに組み合わせることができます。

于 2010-09-12T09:15:40.227 に答える
2

この場合に採用できるアプローチは多数あり、価値を得るために喜んで投入するコストによって異なります。

たとえば、単純なキャストを使用できます。ファクトリからアルゴリズム オブジェクトを取得し、それを適切な (特定の) アルゴリズム オブジェクトにキャストしてから、"Calculate" 関数を呼び出します。

もう 1 つのオプション (さらに多くのコードが必要になる、より一般的なオプション) は、オブジェクト内で使用可能な機能に関する情報を提供するクエリ メカニズムを基本クラス内に提供することです。これは、COM でのインターフェイスのクエリに多少似ています。

自問する必要がある重要な質問は次のとおりです。 1. 特定の機能を実装するために何回必要ですか。2. 基本クラスに起因する追加のポリモーフィズムの問題を解決できる方法はありますか? 3. 派生オブジェクトのユーザーは、特定のオブジェクトを使用していることを知っていますか? それとも、実際の型を知らないようにしたいですか?

一般に、このような場合に私が個人的に行うことは、最も単純な解決策 (この場合は、特定のキャストと関数の呼び出し) から始めて、ドメインに関するデータが増えたら、戻ってリファクタリングすることです。「臭いコード」に敏感な場合は、混乱が多すぎることに気づき、それをより良いソリューションにリファクタリングします。

于 2010-09-12T08:10:16.747 に答える
1

私はこのようにそれを変更します

interface IBusinessRules
{
    string Perform();
    bool CanCalculate { get; }
    string Calculate();
}

抽象基本クラスを追加します(オプションですが、拡張性を高めるために推奨されます)

public abstract class BusinessRules : IBusinessRules {
    protected BusinessRules() { 
    }

    protected virtual bool CanCalculateCore() {
         return false; // Cannot calculate by default
    }

    protected virtual string CalculateCore() { 
         throw new NotImplementedException("Cannot calculate"); 
    }

    protected abstract string PerformCore();

    #region IBusinessRules Members

    public string Perform()
    {
        return PerformCore();
    }

    public bool CanCalculate
    {
        get { return CanCalculateCore(); }
    }

    public string Calculate()
    {
        return CalculateCore();
    }

    #endregion
}

したがって、呼び出しサイトはきれいに見えます。

objBase = objfactory.GetObject(1);
if (objBase.CanCalculate) {
    Console.WriteLine(objBase.Calculate());
}

インターフェイスを拡張する際の大きな問題の 1 つは、そのインターフェイスもサポートしている可能性があるというヒントが呼び出し元にまったく提供されないことです。

于 2010-09-12T11:47:21.023 に答える
0

これはドメインモデリングの問題であり、問​​題のドメインでBusinessRuleとIBaseが意味するものに関連しています。

IBaseですか?と呼ばれるべきだと思いますIBusinessRule。その場合、「ビジネスルール」のコンテキストでの計算とはどういう意味ですか。ドメインで一般的な意味を持つ場合はIBusinessRule、空のメソッドとしてのみ使用する場合でも、他のクラスと同様に実装する必要があります。

ドメインで一般的な意味がない場合、クラスは、Calculateを持つ別のインターフェイスICalculableIAlgorithm?)を実装する必要があります。これを次のように呼び出します。

ICalculable calculable = obj as ICalculable;
if ( calculable != null ) calculable.Calculate();
于 2010-09-12T08:39:44.673 に答える