C# 如果child不';你不知道吗?
我有一个抽象基类C# 如果child不';你不知道吗?,c#,oop,dependency-injection,C#,Oop,Dependency Injection,我有一个抽象基类命令,它依赖于ICommandLogger接口: public abstract class Command { public Command(ICommandLogger cmdLogger) { /* ... */ } } 现在所有的继承者都是这样的: public class ConcreteCommand : Command { public ConcreteCommand(CommandLoggersNamespace.ICommandLogger
命令
,它依赖于ICommandLogger
接口:
public abstract class Command
{
public Command(ICommandLogger cmdLogger) { /* ... */ }
}
现在所有的继承者都是这样的:
public class ConcreteCommand : Command
{
public ConcreteCommand(CommandLoggersNamespace.ICommandLogger cmdLogger)
: base(cmdLogger)
{
}
}
我不喜欢他们被迫知道ICommandLogger
(他们不使用)
怎么避开这个?或者完全重新设计的原因是什么?如果他们不使用命令记录器,您可以尝试根本不设置任何命令记录器,如下所示:
public ConcreteCommand()
: base(null)
{
}
如果这不起作用(抛出一个异常
),您可以尝试实现一个命令记录器并实例化该记录器:
public ConcreteCommand()
: base(new MyPhonyCommandLogger())
{
}
如果不希望这些虚假实例出现,请使用静态可用的单个实例:
public ConcreteCommand()
: base(MyPhonyCommandLogger.Instance)
{
}
我不喜欢他们被迫知道ICommandLogger(他们知道)
不要使用)
他们做得很好;除非您在抽象类中实例化类型为
ICommandLogger
的对象并提供无参数构造函数,否则您当前正在强制继承者了解它。如果您通过构造函数进行依赖项注入,则无法解决此问题。另一种方法是通过属性设置器进行依赖项注入。就我个人而言,我更喜欢构造函数方法,因为对我来说,它传递的是类需要这个依赖项,而属性注入依赖项传递的是可选依赖项
如果您选择构造函数路线,并且您的基类需要很多依赖项,那么您可以通过这样做来减轻一些痛苦,即基类只需要注入一个参数,而不是许多参数。另一种看待它的方式是,
ConcreteComand
类确实依赖于ICommandLogger
。它从命令派生时继承了它
- 因此,除了让
代表其基类接受依赖项之外,您所做的一切都是没有意义的——不要从“ConcreteCommand
有一个ConcreteCommand
”的角度来考虑它,而是更像“Command
是一个ConcreteCommand
命令”
- 考虑一下,如果您能够以某种方式使基类依赖于
以某种方式“潜入”构造ICommandLogger
,您将如何处理想要覆盖基类日志记录行为的问题ConcreteCommand
- 如果您希望能够提供“类似于base”的功能(
)等),并且您绝对不希望base.Log(“foo”)
了解ConcreteComand
,那么您可以始终切换到“has a”类型的场景,即ICommandLogger
只是Command
的一个成员变量(在这种情况下,这是一种愚蠢的理性做法,IMHO!)ConcreteCommand
public abstract class Command
{
public Command(ICommandLogger cmdLogger) { /* ... */ }
}
公共接口ICommandHandler
{
无效句柄(TCommand命令);
}
这将如下所示:
public ConcreteCommand()
: base(null)
{
}
公共类MoveCustomerCommand
{
公共Guid客户ID;
公共广播;
}
公共类MoveCustomerCommandHandler:ICommandHandler
{
公共无效句柄(MoveCustomerCommand命令)
{
//这里的行为。
}
}
此设计的有趣之处在于,由于所有业务逻辑现在都隐藏在一个逻辑后面,并且此接口是通用的,因此使用decorator包装处理程序变得非常容易。例如,日志decorator:
公共类日志CommandHandlerDecorator
:ICommandHandler
{
私有只读ICommandHandler装饰对象;
公共日志CommandHandlerDecorator(
ICommandHandler(用户、ILog日志)
{
this.decoree=decoree;
this.log=log;
}
公共无效句柄(TCommand命令)
{
this.log.log(“正在执行”+typeof(TCommand).Name+”:“+
序列化(命令));
尝试
{
this.decoree.Handle(命令);
}
捕获(例外情况除外)
{
this.log.log(ex);
投掷;
}
}
}
由于此LoggingCommandHandlerDecorator
是通用的,因此它可以包装在任何ICommandHandler
上。这允许使用者依赖某些ICommandHandler
(例如ICommandHandler
)您可以向所有业务逻辑添加横切关注点,而无需更改一行代码
在大多数情况下,这将完全消除使用基类的需要
你可以阅读更多关于这种类型的设计。为什么命令知道抽象ICommandLogger会成为一个问题…?你可以回到属性注入。但是构造函数注入更清晰,因此,更好的选择是IMHO。但是你的
ConcreteCommand
确实知道记录器。只是行为是继承的。这只是一个感知的问题。司机知道他们的车辆的依赖性,这听起来会不会奇怪