3

複数の別々のプラグイン作成者が実装できる抽象オブジェクトがあるとしましょう。(たとえば、バグデータベース接続)ビットのコンシューマーが特定のプラグインタイプごとに処理する必要がないようにします。

また、構成ファイルを解析するプロセスと、データベースプラグインなどを実際に初期化するプロセスを分離したいと思います。

そのために、私は次のようなものを思いついた:

public interface IConfiguration
{
    // No members
}

public interface IConnection
{
    // Members go in here
    void Create();
    void Update();
    void Delete();
}

public interface IConnectionProvider
{
    // Try to interpret file as a configuration, otherwise return null
    IConfiguration ParseConfiguration(Stream configurationContents);
    IConnection Connect(IConfiguration settings);
}

public class ThingyRepository
{
    // Lets say there is a constructor that initializes this with something
    List<IConnectionProvider> providers;

    // Insulates people from the actual connection provider
    KeyValuePair<IConfiguration, IConnectionProvider> Parse(string filename)
    {
        IConnection result = null;
        IConnectionProvider resultProvider = null;
        foreach (var provider in this.providers)
        {
            using (Stream fs = OpenTheFileReadonly(filename))
            {
                IConnection curResult = provider.ParseConfiguration(fs);
                if (curResult == null)
                {
                    continue;
                }
                else
                {
                    if (result == null)
                    {
                        result = curResult;
                        resultProvider = provider;
                    }
                    else
                    {
                        throw new Exception ("ambguity!");
                    }
                }
            }
        }

        if (result == null)
        {
            throw new Exception ("can't parse!");
        }

        return new KeyValuePair<IConfiguration, IConnectionProvider>(
            result, resultProvider);
    }
}

私の質問は、示されたファイルからロードされた設定に対する不透明なハンドルとして機能するはずのこの空のインターフェースを持っているということです。IConnectionProviderの特定の実装者は、ファイルからロードする構成に必要なビットを知っていますが、このライブラリのユーザーはその情報から隔離されている必要があります。

しかし、空のインターフェースを持つことは私には奇妙に思えます。この種のことは理にかなっていますか、それとも私はひどく間違ったことをしましたか?

4

2 に答える 2

2

オブジェクトが何を持っているか、または何をするかを識別するというインターフェイスの通常の仕事の代わりに、単に実装者を何かとして識別する、メンバーを持たないインターフェイスの基本概念は、「フラグ インターフェイス」として知られています。用途はありますが、控えめに使用してください。たとえば、私は通常、これらを階層形式で使用して、特定のデータ ストアに永続化する必要があるドメイン オブジェクトを識別します。

//no direct implementors; unfortunately an "abstract interface" is kind of redundant
//and there's no way to tell the compiler that a class inheriting from this base 
//interface is wrong,
public interface IDomainObject
{
   int Id {get;}
}

public interface IDatabaseDomainObject:IDomainObject { }

public interface ICloudDomainObject:IDomainObject { }

public class SomeDatabaseEntity:IDatabaseDomainObject
{
    public int Id{get;set;}

    ... //more properties/logic
}

public class SomeCloudEntity:ICloudDomainObject
{
    public int Id{get;set;}

    ... //more properties/logic
}

派生したインターフェイスは、オブジェクトがその特定のサブドメインに属していることを除いて、実装オブジェクトの構造について何も新しいことを教えてくれません。

//I can set up a basic Repository pattern handling any IDomainObject...
//(no direct concrete implementors, though I happen to have an abstract)
public interface IRepository<T> where T:IDomainObject
{
    public TDom Retrieve<TDom>(int id) where TDom:T;
}

//... Then create an interface specific to a sub-domain for implementations of
//a Repository for that specific persistence mechanism...
public interface IDatabaseRepository:IRepository<IDatabaseDomainObject>
{
    //... which will only accept objects of the sub-domain.
    public TDom Retrieve<TDom>(int id) where TDom:IDatabaseDomainObject;
}

結果の実装とその使用法をコンパイル時にチェックして、ICloudDomainObject が IDatabaseRepository に渡されていないことを証明できます。このコンパイル時のセキュリティは、属性やプロパティでは不可能です。属性やプロパティは、特別な意味を持つクラスに「フラグを立てる」他の主要な方法です。

要するに、それ自体は悪い習慣ではありませんが、フラグ インターフェイスから何を求めているかを自問し、IConfiguration で一般的に実装される状態または論理データがあるかどうかを自問してください (おそらく、前述の名前またはその他の識別子)構成、または選択したデータストアにロードまたは永続化する方法) は、強制的な標準化で行うことができます。

于 2013-01-22T01:23:36.313 に答える
0

これは完全に正しいと思います。私は、呼び出し元が最初に不透明な「セッション」オブジェクトを取得してから、それを後続の呼び出しに渡す必要がある API を設計しています。

API の実装が異なれば、セッション オブジェクトのまったく異なる実装が使用されるため、セッション オブジェクトは明らかに異なるサブクラスを持つ抽象クラスではありません。それはインターフェースです。セッションオブジェクトには呼び出し元に見える動作がないため、これの唯一の論理モデルはメンバーのないインターフェースであるように思えます。

于 2016-07-18T08:30:37.767 に答える