3

アプリケーションにカスタマイズ フックを挿入する最良の方法は何だろうと考えています。基本的に、私のアプリケーションは 2 つのアセンブリに分割されます。Coreすべてのビジネス ロジックをUserInterface含むアセンブリと、GUI、コントローラー クラス (「パッシブ ビュー」と呼ばれる逸脱した MVC パターンを使用しています)、およびいくつかのヘルパー クラスを含むアセンブリです。コア アセンブリは、他のいくつかのアプリケーションでも使用されます。

私のアプリケーションは、当社が他社からの注文を処理するために使用しています。一般的なプロセスはすべての企業で同じですが、顧客固有の小さな違いがあります。現在、これらの逸脱は、においがするコア アセンブリに直接実装されています。これらの詳細を分離し、顧客ごとに 1 つのオブジェクトにカプセル化して、UserInterface アセンブリに入れることができるすべての顧客固有の詳細を含む中央オブジェクトを作成したいと考えています。

これを達成するためにイベントを使用することを考えました。コア クラスにいくつかのイベントを追加することで、コントローラー クラスは、特定の顧客向けにこれらの逸脱を実装するメソッドをサブスクライブまたはサブスクライブ解除できるようになります。

これを行うには 2 つの方法が考えられます。これらのバインドを手動で追加するか、逸脱したメソッドが存在する場合は自動的に追加するかです。後者については、次のようなことを考えています。

foreach (Order order in form.SelectedOrders) {
    CustomerExtension customer = customerExtensions[order.Customer];

    if(Exists(customer.StatusChanging(...)) // Pseudo Code!
            OrderManager.StatusChanging += new StatusChangingEventHandler(customer.StatusChanging(...));

    order.SetStatus(newStatus);

    if(Exists(customer.StatusChanging(...)) // Pseudo Code!
            OrderManager.StatusChanging -= new StatusChangingEventHandler(customer.StatusChanging(...));
}

これを達成するにはリフレクションを使用する必要があると思いますが、これは何度も実行する必要がある操作に対して実行可能ですか?

または、カスタマイズ フックを追加しながら、顧客ごとに偏差を一元化するより良い方法はありますか?

[編集] 質問を完全に修正しました。

4

3 に答える 3

3

イベントなしでもできると思います(それらはあなたが望む構造ですか?)。私は何かをまとめようとしました: コードを見てみてください (詳細についてあまり気にせずに)、詳しく説明してほしい場合はお知らせください... :-)

// Begin personalization assembly (one of many)-----------------------

/// <summary>
/// Here you could use an attribute to allow clean reflection
/// </summary>
// [CustomerSpecific("Acme")]
public class AcmeCustomization : BaseCustomization
{
    public override void OnStatusChanged()
    {
        base.OnStatusChanged();
        // do what you need to customize
    }
}
// End personalization assembly (one of them)-------------------------

// Begin core assembly -----------------------------------------------
public interface ICustomization
{
    void OnStatusChanged();
}

/// <summary>
/// This class is optional of course, but can be useful
/// </summary>
public class BaseCustomization : ICustomization
{
    public virtual void OnStatusChanged()
    {
        // intentionally empty
    }
}

class CustomizationFactory
{
    public ICustomization GetCustomization(string order)
    {
        // Here you could
        // - hardcode (as you did in your solution)
        // - use reflection (various ways)
        // - use an external mapping file
        // - use MEF (!)
        // and then
        // - do instance caching
        // - whatever...

        // I'm lazy ;-)
        return null;
    }
}

class OrderManager
{
    private ICustomization _customization = null;

    public void SetStatus(string order, int status)
    {
        // Do some work
        this.OnStatusChanged();
        // Do some other work
    }

    protected void OnStatusChanged()
    {
        if (_customization != null)
        {
            _customization.OnStatusChanged();
        }
    }

    public void SetCustomization(ICustomization customization)
    {
        _customization = customization;
    }

    public void ClearCustomization()
    {
        _customization = null;
    }
}
// End core assembly -------------------------------------------------

class Program
{
    static void Main(string[] args)
    {
        CustomizationFactory factory = new CustomizationFactory();
        OrderManager manager = new OrderManager();

        // here I'm just pretending to have "orders"
        var orders = new string[] { 
            "abc",
            "def"
        };

        const int newStatus = 42;

        foreach (var order in orders)
        {
            manager.SetCustomization(factory.GetCustomization(order));
            manager.SetStatus(order, newStatus);
            manager.ClearCustomization();
        }
    }
}

HTH

于 2009-09-02T17:19:57.233 に答える
1

すべての共有機能を含む抽象基本クラスを使用してから、いくつかのフック メソッド (サブクラスでオーバーライドされることを意図した抽象メソッド) を追加するのはどうでしょうか。ここで、各企業の詳細を追加できます。私が説明しようとしているものの擬似コードを次に示します。

abstract class SomeBaseClass
{

   public void DoSomething()
   {
       ...
       somethingElse();
       ...
   }

   abstract void somethingElse();

}

public class CompanyA : SomeBaseClass
{
    void somethingElse()
    {
       // do something specific
    }
}

public class CompanyB : SomeBaseClass
{
    void somethingElse()
    {
       // do something specific
    }
}
于 2009-09-02T06:32:07.403 に答える
0

イベントの使用に関するアイデアを実装しましたが、これまでのところかなり満足しています。

すべての顧客固有のロジックを顧客ごとに 1 つのクラス内に配置することができましたが、コントローラーは対応する顧客固有の機能 (存在する場合) をサブスクライブ/サブスクライブ解除します。Manager クラスにイベントを提供するのが最も簡単な部分でした。

唯一の欠点は、コントローラー クラスのサブスクリプション処理を手動で追加/削除する必要があることです。たとえば、私のSetStatusメソッドは次のようになります。

foreach (Job job in form.SelectedJobs) {
    // Subscribe customer-specific methods to events
    switch (job.Customer.Code) {
            case "VNR":
                    jobManager.JobStatusChanged += new JobManager
                        .JobStatusChangedHandler(Vnr.OnStatusChanged);
                    break;
            case "LS":
                    jobManager.JobStatusChanged += new JobManager
                        .JobStatusChangedHandler(Ls.OnStatusChanged);
                    break;
    }

    jobManager.SetStatus(job, status);

    // Unsubscribe customer-specific methods from events
    switch (job.Customer.Code) {
            case "VNR":
                    jobManager.JobStatusChanged -= new JobManager
                        .JobStatusChangedHandler(Vnr.OnStatusChanged);
                    break;
            case "LS":
                    jobManager.JobStatusChanged -= new JobManager
                        .JobStatusChangedHandler(Ls.OnStatusChanged);
                    break;
    }
}

これは本当にエレガントではありませんが、それほど悪くはありません。

于 2009-09-02T14:18:20.623 に答える