3

C# でプラグ可能なものを作成する方法を知っています。インターフェイスなどを定義しますActivator.CreateInstance(<class>)。または、プラグされたクラスのインスタンスを明示的に作成するコード パスを使用することもできます。多くの方法。

しかし、プラグイン可能にしたいサービスが静的である場合はどうなりますか(そうでないようにリファクタリングできることはわかっていますが、それは問題のポイントではありません)

具体例。ディスク I/O の抽象化 (ファイルの読み取り、ディレクトリの一覧表示など) を提供するクラスがあります。ここで、たとえば実際の FS、データベースからファイルを提供する、この抽象化のさまざまな実装が必要です。

Olivier Jacot-Descombes の返信に基づいて、FileSystemこのような (実際の) クラスを作成します。

public static class FileSystem
{
    static IFSImplemenation s_imple;
    static FileSystem()
    {
        if(<some system setting>)
            // converted to singleton instead of static
            s_imple = new OldFileSystem() 
        else
            s_imple = new DbFileSystem();
    }

    public static byte[] ReadFile(string path)
    {
        return s_imple.ReadFile(path);
    }

    ...
}

繰り返しますが、変更したくない大量のコードがあるため、呼び出し元の署名を同じに保つことが重要でした。このソリューションはそれを実現します。

4

4 に答える 4

5

できません。これは、.NET およびほとんどのオブジェクト指向システム/言語の型システムの制限です。

その理由は、「プラグ可能なもの」(あなたが言及しているように)が効果的であるために はポリモーフィズムが必要だからです。

コントラクト (.NET 用語ではインターフェイス) を定義してから、そのコントラクトを実装します。あなたのシステムは契約のみを扱います。

静的メンバーは .NET ではポリモーフィックではないため、コントラクトを実装することはできません。

ディスク I/O 抽象化の例では、このための静的クラスを作成せず、インターフェイスを作成し、インターフェイスを実装して、インターフェイスを渡します。

もちろん、インターフェイスを使用する利点は、コントラクトの実装の両側を簡単にテストできることです。

  • コントラクトがクライアントである場合、インターフェイスを簡単にモックして、そのモックをコントラクトのコンシューマーに渡すことができます (ここから依存性注入について考え始めることができます) 。
  • システムの残りの部分とは別に実装をテストできます。

ディスク I/O の抽象化の場合、コントラクトを呼び出すすべてのものについて、実際にファイル システムに触れることを心配する必要はありません。コントラクトを (適切なモック セットアップを通じて)触れているかように動作させるだけで済みます。ファイルシステム。

静的メンバーを介して公開されている既存のサービスがあり、それを別の実装と交換する機能が必要な場合は、次のことを行う必要があります。

  • サービスの操作を定義する抽象化 (契約/抽象型) を作成します。
  • 抽象化の実装のインスタンスから静的メソッドに呼び出しを転送する実装を作成します。
  • 実装のインスタンスを使用して、サービスへのすべての静的呼び出しを再配線します。この時点で、何らかの依存性注入を実際に使用する必要があります。そうしないと、呼び出しサイトで具体的な実装を作成するだけになり、それはほとんど同じです (別の実装を使用する場合は、すべての呼び出しサイトを再度変更する必要があります)。
于 2012-10-12T18:35:21.127 に答える
1

静的クラスは「プラグ可能」ではありません。交換できるようにしたい場合は、注入できるインターフェースを使用するようにリファクタリングする必要があります。

一部のクラスには、 ServiceLocator などの静的Currentまたはパラメーターがあります。Default次に、静的コンテキストでServiceLocator.Currentcurrent にアクセスするために使用します。IServiceLocator

これをもう少し進めて、Currentオブジェクトを非表示にすることができます。これを行うことはお勧めしませんが、すべてのコードをリファクタリングする必要がなくなります。Fooただし、この方法では、実装されていないため、メンテナンスがはるかに高くなりますIFoo

静的クラスがあるとしますFoo

static class Foo
{
    public static string GetBar() { return "Bar"; }
}

あなたはインターフェースを作ることができますIFoo

interface IFoo
{
    string GetBar();
}

クラス Foo を次のように変更します

static class Foo 
{
    private static IFoo _foo;

    public static void SetFoo(IFoo foo) { _foo = foo; }

    public static string GetBar() { return _foo.GetBar(); }
}
于 2012-10-12T18:36:05.200 に答える
1

静的クラスを非静的実装のファサードとして使用する

public static class DB
{
    private static IDbInterface _implementation;

    public static void SetImplementation(IDbInterface implementation)
    {
        _implementation = implementation;
    }

    public static Customer GetCustomerByID(int custId)
    {
        return _implementation.GetCustomerByID(custId);
    }

    ...
}
于 2012-10-12T18:39:03.897 に答える
0

ホストアプリケーションに常駐し、実際にはファクトリである静的クラスを作成します。インターフェースによってプラグインによって提供される実装を返します。

于 2012-10-12T18:39:03.990 に答える