1

このシングルトン ファクトリ クラスの例では、ディクショナリを使用して、実行時に関連するレポート クラスを決定します。各レポート サービスが行う必要があることに基づいて、最大 40 の組み合わせがあるためです。

public sealed class ReportServiceFactory : IGetReportServices
{
    private static readonly ReportServiceFactory instance = new ReportServiceFactory();

    private static readonly Dictionary<Tuple<ReportTypes, ReportPeriodTypes>, IServiceReports> reportEntityServices =
        new Dictionary<Tuple<ReportTypes, ReportPeriodTypes>, IServiceReports> {
            { Tuple.Create(ReportTypes.Foo, ReportPeriodTypes.Week), new FooService<FooWeekEntity>() },
            { Tuple.Create(ReportTypes.Foo, ReportPeriodTypes.Month), new FooService<FooMonthEntity>() },

            { Tuple.Create(ReportTypes.Bar, ReportPeriodTypes.Week), new BarService<BarWeekEntity>() },
            { Tuple.Create(ReportTypes.Bar, ReportPeriodTypes.Month), new BarService<BarMonthEntity>() }
        };

    // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
    static ReportServiceFactory()
    {
    }

    private ReportServiceFactory()
    {
    }

    public static ReportServiceFactory Instance
    {
        get { return instance; }
    }

    public IServiceReports Get(ReportTypes reportType, ReportPeriodTypes periodType)
    {
        if (!Enum.IsDefined(typeof(ReportTypes), reportType))
            throw new ArgumentOutOfRangeException("reportType");
        if (!Enum.IsDefined(typeof(ReportPeriodTypes), periodType))
            throw new ArgumentOutOfRangeException("periodType");

        var reportTuple = Tuple.Create(reportType, periodType);

        if (!reportEntityServices.ContainsKey(reportTuple))
            return null;

        return reportEntityServices[reportTuple];
    }
}

ファクトリの関数のより具体的なインターフェイスを返して、例として実行時Get()に変更できるようにしたい...これは、他の呼び出しコードで結果をキャストせずに以下の関数にアクセスできるようにするためです。IServiceFooReportsFooViewModel Get()

public interface IServiceFooReports : IServiceReports
{
    IEnumerable<FooViewModel> Get();
}

public class FooService<T> : IServiceFooReports
{
      ... use EF model context and call .CreateObjectContext<T>()
      do filtering on the IQueryable result and return the result materialised as the relevant view models
}

これは可能ですか?これも変更が必要な場合のIGetReportServicesインターフェースです。IServiceReportsは空で、現在、これらのレポート サービスを同じディクショナリに格納する方法としてのみ使用されています... マーカー インターフェイスですか?

public interface IGetReportServices
{
    IServiceReports Get(ReportTypes reportType, ReportPeriodTypes reportPeriodType);
}
4

2 に答える 2

1

もちろん。インターフェイスは他のインターフェイスを継承できます。その場合、クラス継承を使用する場合と同様に、ポリモーフィズムを使用して、それらが表す型の間で変換できます。簡単な例として、次のインターフェースがあるとします。

public interface IFoo
{
    string Get();
}

public interface IBar : IFoo
{
    new string Get();
}

および次のクラス:

public class MyClass : IBar
{
    public string Get()
    {
        return @"some data";
    }
}

次に、次のメソッドを実装できます。

public MyClass SomeMethod()
{
    MyClass myVariable = new MyClass();
    return myVariable;
}

そして、そのメソッドを呼び出して、「MyClass」によって明示的に実装されていないインターフェイスによって定義された型の変数を設定しますが、MyClass実装するインターフェイスによって定義されます。つまり、

IFoo myOtherVariable = SomeMethod() as IFoo;

NB: ポイントは、MyClass が「IFoo」を明示的に実装していないことです。「IFoo」を継承する「IBar」のみを実装します。

したがって、インターフェイス IServiceFooReports が IServiceReports を実装し、メソッドの内部動作がタイプ「IServiceFooReports」のオブジェクトを作成する場合、上記の情報を問題に適用すると、タイプ「IServiceReports」を介してそのオブジェクトを返すことができます。メソッドの外では、「as」キーワードを使用して、出力をより具体的なタイプ「IServiceFooReports」に安全にキャストできるはずです。

于 2013-07-18T23:55:48.387 に答える