两种可能的编程模式,哪一种更合适?

时间:2014-05-26 08:05:25

标签: c# linq design-patterns remote-server template-specialization

我正在开发一个新的.Net库,它需要简化我们服务器的接口。我喜欢LINQ,而我目前的设计受其影响很大。

目前我知道这项任务的两种可能的编程模式,但我无法确定哪一种更清洁。在C ++中,我会使用模板专业化,但我不能在C#中使用它。

我可以使用一个通用基接口,然后指定派生接口,它们添加一些特殊方法并覆盖(隐藏)一些派生方法:

interface ISelection<out T> {
    ISelection<T> Skip(int n);
    ISelection<T> Method2();
    ISelection<T> Method3();
    ISelection<T> Method4();

    ISelection<TResult> Select<TResult>(Func<T, TResult> selector);
    IDateTimeSelection Select(Func<T, DateTime> selector);

    IResult<T> Submit();
}

interface IDateTimeSelection : ISelection<DateTime> {
    new IDateTimeSelection Skip(int n);
    new IDateTimeSelection Method2();
    new IDateTimeSelection Method3();
    new IDateTimeSelection Method4();

    IDateTimeSelection SpecialMethod();
}

我还考虑 curiously recurring template pattern 以避免派生方法的重写(隐藏)。

interface IBaseSelection<out Selection, out T> where Selection : IBaseSelection<Selection, T> {
    Selection Skip(int n);
    Selection Method2();
    Selection Method3();
    Selection Method4();

    ISelection<TResult> Select<TResult>(Func<T, TResult> selector);
    IDateTimeSelection Select(Func<T, DateTime> selector);

    IResult<T> Submit();
}

interface ISelection<out T> : IBaseSelection<ISelection<T>, T> {
}

interface IDateTimeSelection : IBaseSelection<IDateTimeSelection, DateTime> {
    IDateTimeSelection SpecialMethod();
}

最后,我需要能够做到以下几点:

ISelection<Dataset> datasets = ...
var result = datasets
    .Select(dataset => dataset.Date)
    .Skip(5)
    .SpecialMethod()
    .Submit();

我希望你能告诉我应该使用哪种方法,甚至说服我使用更好的方法。

PS:我不能使用扩展方法作为模板专业化的解决方法。

4 个答案:

答案 0 :(得分:2)

可能与G.Y.相同。意思是,但我会扩展它,为你的案例展示解决方案。

public interface ISelection<out T>
    where T : ISelection<T>
{
    T Skip(int n);
    T Method2();
    T Method3();
}

public interface IDateTimeSelection<out T> : ISelection<T>
    where T : IDateTimeSelection<T>
{
    T SpecialMethod();
}

public class Implementation : IDateTimeSelection<Implementation>
{
    public Implementation Skip(int n)
    {
        return this;
    }

    public Implementation Method2()
    {
        return this;
    }

    public Implementation Method3()
    {
        return this;
    }

    public Implementation SpecialMethod()
    {
        return this;
    }
}

最后你可以这样做:

        var impl = new Implementation2();
        impl.Skip(2).Method2().Method3().SpecialMethod().Method2();

如果我理解正确,这就是CRTP在C#中的实现方式。您的CRTP示例非常复杂,有什么理由吗?

答案 1 :(得分:2)

我在过去几周内经常使用“奇怪的重复模板模式”来启用方法链接。

但是我碰巧注意到这有一个警告:每个特殊类都继承了不同的接口。虽然它们都是由相同的源代码定义的,但泛型类型参数的差异实际上会使它们成为不同的类型。例如,如果您想将不同类型的ISelection-s放入一个集合中,则会出现问题。

除非您<T> <out T>。这反过来意味着你只能“输出”,即返回T类型的对象,但不能将它们作为参数。

答案 2 :(得分:0)

这是一个艰难的选择。想想未来。什么是预期的变化,新的功能?它会对这两种实现产生什么影响。考虑开闭原理,松耦合/高内聚。

您不希望最终出现基本接口有10个函数的情况,某些实现只能实现一个小子集,并为其余部分抛出NotDefined异常。

第一种方法是松散耦合。通过定义基本选择类,所有实现类都有一种约束来使用基本方法。使用第二种方法时我会非常小心。

我建议对两种接口的方法进行原型设计,看看它是如何进行的。

答案 3 :(得分:-1)

您可以尝试将其作为原型并从中演变吗?

    public interface ISelection<out T>
    {
        T Skip(int n);
        T Method2();
        T Method3();
        T Method4();
        T SpecialMethod();
    }