添加附加功能的继承替代方案

Alternatives to inheritance to adding additional functionality

问题:Windows.Forms 框架中有两个 class 已经相互继承(BindingNavigator 和 ToolStrip),因此无法插入继承。扩展两个具有相同功能的不同 class 的选项或最佳选项是什么(为了 UI 一致性)?

我在装饰器方面取得了一些成功,但这需要转换到共享接口。

我已经设法使用策略模式的变体以及 c# 8 默认接口使其正常工作。每个扩展 class 都有一个具有所有附加功能的辅助对象。我从助手 class 中提取了一个接口,向其添加了一个助手参数,扩展的 classes 实现了它。 Helper 传递给父级,而接口重新映射方法,使它们直接显示。 (添加() => Helper.Add())。这样所有功能都显示在扩展 class 上,就好像它是继承的一样,并且 classes 可以完全无关。

public class ToolStripCustomUI
{
    private ToolStrip _toolStrip;
    public ToolStripButton ButtonAdd { get; set; } = new();
    public ToolStripButton ButtonDelete { get; set; } = new();
    // more controls
    public ToolStripCustomUI(ToolStrip toolStrip)
    {
        _toolStrip = toolStrip;
        Setup();
    }
    public void Setup() { // do stuff }
    // More methods
}
public interface ICustomToolStrip
{
    public ToolStripButton ButtonAdd 
    { 
        get => CustomUI.ButtonAdd; 
        set => CustomUI.ButtonAdd = value; 
    }        
    public ToolStripButton ButtonDelete 
    { 
        get => CustomUI.ButtonDelete; 
        set => CustomUI.ButtonDelete = value; 
    }
    // more controls
    ToolStripCustomUI CustomUI { get; }
    public void Setup() => CustomUI.Setup();
    // Other methods
}
public class ToolStripDecorator : ToolStrip, ICustomToolStrip
{
    public ToolStripCustomUI CustomUI 
       => new ToolStripCustomUI(this);
    public ToolStripDecorator() 
       => CustomUI.Setup();
}
public class CustomBindingNavigator : BindingNavigator, ICustomToolStrip
{
    public ToolStripCustomUI CustomUI => new 
    ToolStripCustomUI(this);
    public CustomBindingNavigator() : base(true)
    {
        Items.Remove(AddNewItem);
        Items.Remove(DeleteItem);
        CustomUI.Setup();
    }
}

有没有更好更正确的做法?

这是一种使用针对您的自定义界面的扩展方法的方法。扩展方法是静态 class 上的一种特殊静态方法,允许您将新功能附加到任何 class 或接口。

有关扩展方法的更多信息here

我删除了所有实现细节以演示类型如何连接。

public class ToolStrip { }
public class BindingNavigator { }
public static class CustomToolStripExtensions
{
    public static void Setup<T>( this T target )  where T: ICustomToolStrip
    {
        // do setup work here!
    }
}
public interface ICustomToolStrip { }
public class ToolStripDecorator : ToolStrip, ICustomToolStrip
{
    public ToolStripDecorator()
    {
        this.Setup<ToolStripDecorator>();
    }
}
public class CustomBindingNavigator : BindingNavigator, ICustomToolStrip
{
    public CustomBindingNavigator()
    {
        this.Setup<CustomBindingNavigator>();
    }
}

我确定的解决方案是完全不直接扩展 ToolStrip 或 BindingNavigator。相反,我创建了一个新的 CustomToolStrip class,它有一个 ToolStrip 对象作为 属性,并将所有新功能添加到 Toolstrip 对象。然后,我创建了一个扩展 CustomToolStrip 的 CustomBindingNavigator class,并添加了所有 BindingNavigator 特定功能。 ToolStrip 属性 我覆盖了它以使其成为 BindingNavigator。

在自定义工具条中

private virtual ToolStrip ToolStrip { get; set; } = new ToolStrip();

在 CustomBindingNavigator 中

private override ToolStrip ToolStrip {get; set;} = new BindingNavigator();

然后可以注入工具条以成为装饰器模式。