单个类上同一接口的多个实现的替代方法
本文关键字:实现 方法 接口 单个类 | 更新日期: 2023-09-27 17:56:25
假设有一个公共用户页控件,它提供操作并在大多数应用程序页上重用。常见操作,例如:保存,取消,重置,发送等。它目前大约有10个。
特定操作状态通常(但不一定)取决于页面上显示的实体及其状态。在创建新的实体实例的情况下,可以显示并启用"保存并取消"。但是,当我们编辑现有的保存,取消和重置可能是主动显示的操作时。
操作公共控件和页面之间的通信
由于这个带有操作的通用控件是状态分离的,并且不知道页面的上下文(或实体类型及其状态),因此我决定给它注入钩子,以便页面可以提供通用控件随后将使用的操作按钮获取器。
我没有定义事件和委托,而是决定做一个简化类型的大致相同的场景。我刚刚使用了Func<bool>
属性,但它们可以很容易地转换为事件/委托。仍然是目前定义它们的方式(发送操作的示例):
private Func<bool> DefaultState = () => false;
private Func<bool> isSendVisible;
public Func<bool> IsSendVisible
{
private get { return isSendVisible ?? DefaultState; }
set { isSendVisible = value; }
}
private Func<bool> isSendEnabled;
public Func<bool> IsSendEnabled
{
private get { return isSendEnabled ?? DefaultState; }
set { isSendEnabled = value; }
}
问题是我已经在接口中定义了这两个属性:
public interface ISendActionProvider
{
Func<bool> IsSendVisible { set; }
Func<bool> IsSendEnabled { set; }
}
我的公共控件实现了此接口(以及其他操作的接口),但其他控件(甚至页面本身)可以提供相同的接口,因此可以在多个位置显示相同的按钮,并重复使用相同的操作状态机制。页面只需在初始化期间将其 getter 绑定到提供程序,以便操作提供程序可以适当地设置操作的状态。
问题所在
问题是,对于每个新操作,我都必须为其添加相同的接口和实现,这会导致相当多的半重复代码。
如果我能有一个接口并为每个操作实现它,那就太好了,这样它就可以由单个类(操作提供程序类 - 在我的例子中是提供这些操作的公共控件)多次实现。这在 C# 中工作的唯一方法是拥有一个通用接口,然后根据需要提供尽可能多的实现。但是我没有区分泛型类型来提供多个泛型接口实现。
public interface IActionProvider // multiple inplementations?
{
Func<bool> IsActionVisible { set; }
Func<bool> IsActionEnabled { set; }
}
实现的工作方式(如上所示)是每个操作都定义了其默认行为,但特定页面可以通过为特定操作提供自己的 getter 来提供其状态来覆盖它。
我有哪些可能性来整合我的代码?
我想要的是某种可以在初始化绑定期间调用的通用属性提供程序:
(provider as IActionProvider<TSend>).IsActionVisible<TSend> = this.IsSendVisible;
但如前所述,我没有这种区分泛型类型。
一种可能的解决方案
注意:我自己用一个我不太喜欢但可以做需要的解决方案来回答这个问题。我还在等待更好的建议。
与其有多个接口及其实现,我只能有一个定义略有不同的接口:
public interface IActionProvider
{
void SetVisibleGetter(ActionType type, Func<bool> getter);
void SetEnabledGetter(ActionType type, Func<bool> getter);
}
然后,实现可以为单个操作类型使用某种字典:
private IDictionary<ActionType, Func<bool>> isActionVisible = new Dictionary<ActionType, Func<bool>> {
{ ActionType.Cacel, AlwaysFalse }
{ ActionType.Send, AlwaysFalse },
...
};
public void SetVisibleGetter(ActionType type, Func<bool> getter)
{
this.isActionVisible[type] = getter ?? this.isActionVisible[type];
}
...
然后在需要设置操作状态的操作提供程序控件中使用它,如下所示:
linkSend.Visible = this.isActionVisible[ActionType.Send]();
您可以提供默认实现并使用继承来覆盖默认实现。
例如
public class SubmitActionProvider:ActionProvider
{
public override Func<bool> IsActionVisible
{
get
{
Console.WriteLine("submit");
return null;
}
}
}
public class CancelActionProvider : ActionProvider
{
public override Func<bool> IsActionVisible
{
get
{
Console.WriteLine("cancel");
return null;
}
}
}
public class ActionProvider
{
public virtual Func<bool> IsActionVisible { get { Console.WriteLine("Default implementation"); return null; } }
public virtual Func<bool> IsActionEnabled { set { } }
}