实现通用行为来替代抽象基类?

发布于 2024-09-06 05:07:04 字数 827 浏览 1 评论 0原文

在 C# 中,我有一个类层次结构,在顶部有几个抽象基类和相当数量的派生类。其中一些具体类具有一些相同实现的共同属性和方法。我觉得这很浪费,因此一种解决方案可能是在另一个抽象基类中实现这种常见行为。

abstract class Control;

abstract class SquareControl: Control
{
    public int SquarishProperty;
    public void SquarishMethod();
};

class Window: SquareControl;
class Button: SquareControl;

但是,如果层次结构中的其他几个类共享一些其他行为,但也与另一个基类的控件之一共享一些共同点,该怎么办?也许有很多共同点。使用抽象基类实现对此进行建模将变得不切实际,不是吗?

abstract class FlashableControl: Control
{
    public int FlashyProperty;
    public void FlashMethod();
};

class StatusBar: FlashableControl;  // but it's also a bit square too, hmm...

那么,如何在不使用基类的情况下跨类共享此类实现呢?

我想我想将接口的实现委托给另一个类,并让该类代表所需的类实现这些属性和方法,以便对用户来说,StatusBar 和 Window 看起来支持标准接口,但在涵盖了它的其他实现它的东西。

我可以想象实现此行为的聚合类,但这是否合适并且是否存在任何陷阱?有哪些替代方案?

谢谢

In C#, I have a class hierarchy with a couple of abstract base classes near the top and a fair number of derived classes. A few these concrete classes have some common properties and methods that are implemented identically. It strikes me as wasteful and so one solution might be to implement this common behaviour in another abstract base class.

abstract class Control;

abstract class SquareControl: Control
{
    public int SquarishProperty;
    public void SquarishMethod();
};

class Window: SquareControl;
class Button: SquareControl;

However, what if several other classes in the hierarchy shared some other behaviour but also share something in common with one of the controls from another base class? Perhaps there are lots of areas of commonality. It would become impractical to model this with abstract base class implementation wouldn't it?

abstract class FlashableControl: Control
{
    public int FlashyProperty;
    public void FlashMethod();
};

class StatusBar: FlashableControl;  // but it's also a bit square too, hmm...

So how do you go about sharing such implementations across classes without using base classes?

I imagine I want to delegate the implementaion of an interface to another class and have that class implement those properties and methods on behalf of the desired classes, so that to the user, the StatusBar and Window appear to support a standard interface, but under the covers it's something else that implements it.

I can visualise aggregating classes that implement this behaviour, but is this appropriate and are there any pitfalls? What are the alternatives?

Thanks

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

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

发布评论

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

评论(3

狼性发作 2024-09-13 05:07:04

您可以使用这样的模式:

public interface ICommonServices
{
    string SomeProperty { get; set; }

    void SomeMethod(string param);
}

public static class CommonServiceMethods
{
    public static void DoSomething(this ICommonServices services, string param)
    {
        services.SomeMethod(services.SomeProperty + ": " + param + " something extra!");
    }
}

所有实现 ICommonServices 的类现在还可以通过扩展方法获得一些自由行为,这仅取决于所有 ICommonServices 实现者公开的那些功能。如果您需要访问基类功能,您可以将其放入其自己的接口中,并让 ICommonServices 也实现该接口。现在,您可以为接口创建“默认”扩展功能,而无需使用多个基类。


编辑

如果您希望其中一些方法是内部的,您可以像这样修改模式:

public class MyObject : IServices
{
    public string PublicProperty { get; private set; }

    string IServices.SomeProperty { get; set; }

    void IServices.SomeMethod(string param)
    {
        //Do something...
    }
}

public interface IPublicServices
{
    string PublicProperty { get; }
}

internal interface IServices : IPublicServices
{
    string SomeProperty { get; set; }

    void SomeMethod(string param);
}

internal static class ServiceMethods
{
    public static void DoSomething(this IServices services, string param)
    {
        services.SomeMethod(services.SomeProperty + ": " + param + " something extra!");
    }
}

基本上我们公开了公共和内部接口。请注意,我们显式实现内部接口方法,因此这些方法不可用于公共使用(因为公共客户端无法访问接口类型。)在这种情况下,帮助器扩展方法是内部的,依赖于内部接口,尽管您也可以创建依赖于公共接口的公共帮助器方法。

You can use a pattern like this:

public interface ICommonServices
{
    string SomeProperty { get; set; }

    void SomeMethod(string param);
}

public static class CommonServiceMethods
{
    public static void DoSomething(this ICommonServices services, string param)
    {
        services.SomeMethod(services.SomeProperty + ": " + param + " something extra!");
    }
}

All classes that implement ICommonServices now also get some free behavior via the extension method, which depends solely on those features exposed by all ICommonServices implementers. If you need access to base class functionality, you can put that in its own interface and have ICommonServices implement that interface as well. Now you can create 'default' extension functionality for interfaces without having to use multiple base classes.


EDIT

If you want some of these methods to be internal, you can modify the pattern like this:

public class MyObject : IServices
{
    public string PublicProperty { get; private set; }

    string IServices.SomeProperty { get; set; }

    void IServices.SomeMethod(string param)
    {
        //Do something...
    }
}

public interface IPublicServices
{
    string PublicProperty { get; }
}

internal interface IServices : IPublicServices
{
    string SomeProperty { get; set; }

    void SomeMethod(string param);
}

internal static class ServiceMethods
{
    public static void DoSomething(this IServices services, string param)
    {
        services.SomeMethod(services.SomeProperty + ": " + param + " something extra!");
    }
}

Basically we're exposing both public and internal interfaces. Note that we implement the internal interface methods explicitly, so that the methods are not available for public consumption (since the public client can't get access to the interface type.) In this case, the helper extension methods are internal, relying on the internal interface, though you could also create public helper methods that rely on the public interface.

我做我的改变 2024-09-13 05:07:04

您可以使用“has-a”代替“is-a”并委托给内部方形控件

    class Window : Control, ISquareControl
    {
        private SquareControl square;

        public void SquareOperation()
        {
            square.SquareOperation();
        }
    }

    class SquareControl : Control, ISquareControl
    {
        public void SquareOperation()
        {
            // ...
        }
    }

You could use 'has-a' instead of 'is-a' and delegate to an internal square control

    class Window : Control, ISquareControl
    {
        private SquareControl square;

        public void SquareOperation()
        {
            square.SquareOperation();
        }
    }

    class SquareControl : Control, ISquareControl
    {
        public void SquareOperation()
        {
            // ...
        }
    }
夜清冷一曲。 2024-09-13 05:07:04

一种方法是使用接口和基类。

Flashable 将成为一个很好的接口而不是一个类。

One way is to use Interfaces and Base Classes.

Flashable would make a good Interface instead of a class.

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