当实现类被密封时覆盖单个接口方法

发布于 2024-11-30 15:44:51 字数 1855 浏览 4 评论 0原文

这可能是最容易用代码解释的(这当然不是实际的代码,但它具有相同的属性):

我有一个看起来像这样的接口:

    public interface ISomeProvider
    {
        object GetFoo1(); //<-- This needs caching

        //These others don't
        object GetFoo2();
        object GetFoo3();

        //And let's say 20 more
    }

这有一个像这样的实现:

    //NOTE: Sealed class otherwise we could inherit from it
    public sealed  class SuperCleverProvider : ISomeProvider
    {
        public object GetFoo1()
        {
            return "a";
        }

        public object GetFoo2()
        {
            return "b";
        }

        public object GetFoo3()
        {
            return "b";
        }
    }

现在,让我们进行其中一个调用说 GetFoo1 确实很重,所以我想提供一个新版本的接口,其中使用旧接口的实例缓存对它的调用。

我现在正在这样做:

    public class CachedSuperCleverProvider : ISomeProvider
    {
        private readonly SuperCleverProvider _provider;

        public CachedSuperCleverProvider(SuperCleverProvider provider)
        {
            _provider = provider;
        }

        private object UsingCache<T>(string cacheKey, Func<T> eval)
        {
            //Pretend this does caching. This is not related to the question
            throw new NotImplementedException();
        }

        public object GetFoo1()
        {
            return UsingCache("foo1", _provider.GetFoo1);
        }

        //The code below this point is what I want to get rid of
        public object GetFoo2()
        {
            return _provider.GetFoo2();
        }

        public object GetFoo3()
        {
            return _provider.GetFoo3();
        }

        //And so on for all the rest
    }

这有两个问题(至少):

  • 每次有人向接口添加一个方法时,我都必须去更改它,即使我不希望缓存这个新方法,
  • 我也会得到这么大的结果仅调用底层实现的无用代码列表。

谁能想出一种不存在这些问题的方法吗?

This is probably easiest to explain with code (this is of course not the actual code but it has the same properties):

I have an interface that looks something like this:

    public interface ISomeProvider
    {
        object GetFoo1(); //<-- This needs caching

        //These others don't
        object GetFoo2();
        object GetFoo3();

        //And let's say 20 more
    }

And this has an implementation like this:

    //NOTE: Sealed class otherwise we could inherit from it
    public sealed  class SuperCleverProvider : ISomeProvider
    {
        public object GetFoo1()
        {
            return "a";
        }

        public object GetFoo2()
        {
            return "b";
        }

        public object GetFoo3()
        {
            return "b";
        }
    }

Now one of these calls, let's say GetFoo1 is really heavy so I want to provider a new version of the interface where calls to it are cached using an instance of the old one.

I'm doing it like this at the moment:

    public class CachedSuperCleverProvider : ISomeProvider
    {
        private readonly SuperCleverProvider _provider;

        public CachedSuperCleverProvider(SuperCleverProvider provider)
        {
            _provider = provider;
        }

        private object UsingCache<T>(string cacheKey, Func<T> eval)
        {
            //Pretend this does caching. This is not related to the question
            throw new NotImplementedException();
        }

        public object GetFoo1()
        {
            return UsingCache("foo1", _provider.GetFoo1);
        }

        //The code below this point is what I want to get rid of
        public object GetFoo2()
        {
            return _provider.GetFoo2();
        }

        public object GetFoo3()
        {
            return _provider.GetFoo3();
        }

        //And so on for all the rest
    }

This has two problems (at least):

  • Every time someone adds a method to the interface I have to go change this even though I dont want this new method to be cached
  • I get this huge list of useless code that just call through to the underlying implementation.

Can anyone think of a way of doing this that doesn't have these problems?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

深居我梦 2024-12-07 15:44:51

三个选项:

  • 自动生成类
  • 使用 PostSharp 或类似的东西以更基于拦截器的方式执行此操作
  • 接受它就

我个人而言,我可能会选择第三种选择,除非您真的发现自己经常这样做。权衡每个选项的成本 - 您实际上要花费多少时间来添加此委托?

就我个人而言,我希望将此类事情视为一种语言功能 - “通过此字段委托此接口,除非我覆盖它”,但显然目前不存在......

Three options:

  • Autogenerate the class
  • Use PostSharp or something similar to do it in a more interceptor-based way
  • Live with it

Personally I'd probably go with the third option, unless you really find yourself doing this a lot. Weigh up the cost of each option - how much time are you actually going to spend adding this delegation?

Personally I'd like to see this sort of thing as a language feature - "delegate to this interface via this field unless I override it" but obviously that's not present at the moment...

哭了丶谁疼 2024-12-07 15:44:51

这就是我的建议。虽然并没有好多少,但会简化包装过程。

创建一个类 SomeProviderWrapper

public class SomeProviderWrapper : ISomeProvider
{
    protected ISomeProvider WrappedProvider { get; private set; }

    protected SomeProviderWrapper(ISomeProvider wrapped)
    {
        if (wrapped == null)
            throw new ArgumentNullException("wrapped");

        WrappedProvider = wrapped;
    }

    public virtual object GetFoo1()
    {
        return WrappedProvider.GetFoo1();
    }

    public virtual object GetFoo2()
    {
        return WrappedProvider.GetFoo2();
    }

    public virtual object GetFoo3()
    {
        return WrappedProvider.GetFoo3();
    }
}

现在包装已被归入其自己的类,您可以编写缓存版本:

public class CachedSuperCleverProvider : SomeProviderWrapper
{
    public CachedSuperCleverProvider(ISomeProvider wrapped) : base(wrapped) { }

    private object UsingCache<T>(string cacheKey, Func<T> eval)
    {
        throw new NotImplementedException();
    }

    public override object GetFoo1()
    {
        return UsingCache("foo1", WrappedProvider.GetFoo1);
    }
}

这可以使委托代码远离您的超级聪明的提供程序。您仍然需要维护委托代码,但它不会污染缓存提供程序的设计。

Here's what I'd suggest. It's not too much better, but will simplify the wrapping process.

Create a class SomeProviderWrapper:

public class SomeProviderWrapper : ISomeProvider
{
    protected ISomeProvider WrappedProvider { get; private set; }

    protected SomeProviderWrapper(ISomeProvider wrapped)
    {
        if (wrapped == null)
            throw new ArgumentNullException("wrapped");

        WrappedProvider = wrapped;
    }

    public virtual object GetFoo1()
    {
        return WrappedProvider.GetFoo1();
    }

    public virtual object GetFoo2()
    {
        return WrappedProvider.GetFoo2();
    }

    public virtual object GetFoo3()
    {
        return WrappedProvider.GetFoo3();
    }
}

Now that the wrapping is relegated to its own class, you can write the caching version:

public class CachedSuperCleverProvider : SomeProviderWrapper
{
    public CachedSuperCleverProvider(ISomeProvider wrapped) : base(wrapped) { }

    private object UsingCache<T>(string cacheKey, Func<T> eval)
    {
        throw new NotImplementedException();
    }

    public override object GetFoo1()
    {
        return UsingCache("foo1", WrappedProvider.GetFoo1);
    }
}

This keeps the delegation code out of your super clever provider. You will still have to maintain the delegation code, but it won't pollute the design of your caching provider.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文