C# 如何重构此条件以使用多态性?
我刚看完YouTube上的Google clean code视频(参见,第一篇文章),内容是关于从代码中删除C# 如何重构此条件以使用多态性?,c#,.net,polymorphism,C#,.net,Polymorphism,我刚看完YouTube上的Google clean code视频(参见,第一篇文章),内容是关于从代码中删除if语句并改用多态性 看了视频后,我看了看视频前我正在写的一些代码,注意到一些地方我可以使用这种方法,主要是在一些地方,同样的逻辑被多次实现。举个例子: 我有一些这样的代码 public int Number { get { string returnValue; if (this.internalTableNumber == null)
if
语句并改用多态性
看了视频后,我看了看视频前我正在写的一些代码,注意到一些地方我可以使用这种方法,主要是在一些地方,同样的逻辑被多次实现。举个例子:
我有一些这样的代码
public int Number
{
get
{
string returnValue;
if (this.internalTableNumber == null)
returnValue = this.RunTableInfoCommand(internalTableName,
TableInfoEnum.TAB_INFO_NUM);
else
returnValue = this.RunTableInfoCommand(internalTableNumber.Value,
TableInfoEnum.TAB_INFO_NUM);
return Convert.ToInt32(returnValue);
}
}
RunTableInfoCommand所做的并不重要,但最重要的是,我有许多属性与的属性完全相同,如果Statement唯一改变的是TableInfoEnum
我想知道是否有人能帮助我重构这个函数,使它仍然做同样的事情,但是没有任何<代码> < < /Cord>语句> < /P> < P>我可能会考虑将返回值的取取到可在运行时注入的另一个类。
public class Thing
{
public IValueFetcher ValueFetcher { get; set; }
public int Number
{
get
{
return this.ValueFetcher.GetValue<int>(/* parameters to identify the value to fetch */);
}
}
}
公共类的东西
{
public IValueFetcher ValueFetcher{get;set;}
公共整数
{
得到
{
返回此.ValueFetcher.GetValue(/*参数,用于标识要获取的值*/);
}
}
}
这将处理大量重复的代码,并减少对接口值源的依赖
我认为在某个时候,您可能会有一个if语句,因为您仍然需要决定要调用哪个版本的RunTableInfoCommand。您实际上将实现类似于策略模式的内容。首先定义一个超级类,让我们称之为AbstractTableInfoCommand。此类可能是抽象的,但必须指定名为runTableInfoCommand()的方法 然后可以定义几个子类,每个子类实现runTableInfoCommand()方法。然后,您的类(具有Number属性的类)将具有AbstractTableInfoCommand类型的新属性(我们称之为tableInfoCommand),该属性将被实例化为AbstractTableInfoCommand的一个具体子类 代码将是:
public int Number
{
get
{
return this.tableInfoCommand.runTableInfoCommand();
}
}
因此,您可以创建NullTableInfoCommand和其他tableinfocommand等。其优点是,如果您有返回tableinfocommand的新条件,则可以添加新类,而不是编辑此代码
尽管如此,并非所有情况都适合这种模式。因此,它使代码更具可扩展性,但如果您所处的环境不要求可扩展性,则可能会有点过头。我假设
internTableName
和InternalTableNumber
是同一事物的某种价值。为什么不将其封装在类中,并将该类的实例传递给this.RunTableInfoCommand,如下所示:
public int Number
{
get
{
string returnValue;
internalTableClass myinstance(parameters);
return Convert.ToInt32(this.RunTableInfoCommand(myinstance, TableInfoEnum.TAB_INFO_NUM));
}
}
如果您仍然希望使用多态性,那么可以在该类中通过重载来实现,例如,返回数字或名称的giveInternalTableIdentifier
此处的代码可能如下所示:
public int Number
{
get
{
string returnValue;
internalTableClass myinstance(parameters);
return Convert.ToInt32(this.RunTableInfoCommand(myinstance.giveInternalTableIdentifier, TableInfoEnum.TAB_INFO_NUM));
}
}
internalTableClass的代码将非常简单(使用:internalAbstractTableClass,以及从中继承的两个类,一个给出名称,另一个给出数字)编辑2我将如何真正解决这个问题 我会使InternalTableNumber成为延迟加载的属性。如果它不可用,那么我将通过InternalTableName查找它。然后我总是对我的方法使用InternalTableNumber属性
private int? internalTableNumber;
private int InternalTableNumber
{
get
{
if (!internalTableNumber.HasValue)
{
internalTableNumber = GetValueFromTableName( internalTableName );
}
return internalTableNumber;
}
set
{
internalTableNumber = value;
}
}
public int Number
{
get
{
string value = this.RunTableInfoCommand(InternalTableNumber,
TableInfoEnum.TAB_INFO_NUM);
return Convert.ToInt32( value );
}
}
使用多态性编辑
假设您当前的类名为Foo,那么我会将其重构为两个类,FooWithName和FooWithNumber。FooWithName是您拥有表名时使用的类,FooWithNumber是您拥有表号时使用的类。然后,我将用一个数字方法编写每个类——实际上,我还将编写一个接口IFoo,每个接口都将实现,以便它们可以互换使用
public interface IFoo
{
int Number { get; }|
}
public class FooWithName : IFoo
{
private string tableName;
public FooWithName( string name )
{
this.tableName = name;
}
public int Number
{
get { return this.RunTableInfoCommand(this.tableName,
TableInfoEnum.TAB_INFO_NUM);
}
... rest of class, including RunTableInfoCommand(string,int);
}
public class FooWithNumber : IFoo
{
private int tableNumber;
public FooWithNumber( int number )
{
this.tableNumber = number;
}
public int Number
{
get { return this.RunTableInfoCommand(this.tableNumber,
TableInfoEnum.TAB_INFO_NUM);
}
... rest of class, including RunTableInfoCommand(int,int);
}
您可以这样使用它:
IFoo foo;
if (tableNumber.HasValue)
{
foo = new FooWithNumber( tableNumber.Value );
}
else
{
foo = new FooWithName( tableName );
}
int number = foo.Number;
显然,除非在现有类中有很多if-then-else构造,否则这个解决方案实际上并没有太多改进。这个解决方案使用多态性创建IFoo,然后只使用接口方法,而不考虑实现。这可以很容易地扩展为在一个抽象类中继承RunTableCommand(int)的通用实现,该抽象类继承IFoo,并且是FooWithNum和FooWithName的基类。我将重构它,从而:
table = this.internalTableNumber == null ? internalTableName : internalTableNumber.Value;
return Convert.ToInt32(this.RunTableInfoCommand(table, TableInfoEnum.TAB_INFO_NUM));
喜欢三元运算符。在看到这些(技术上正确的)响应之后,这里只是一个警告,去掉If语句不应该是你的唯一目标,目标应该是使代码可扩展、可维护和简单,如果这意味着去掉If语句,那就太好了,但它本身不应该是一个目标
在您给出的代码示例中,在不了解您的应用程序的情况下,假设您不打算对空值的测试进行太多的扩展,我认为If(或者甚至三元)是更易于维护的解决方案,可以非常坦率地说。我觉得您的代码非常好。可读的。简单。(我希望它能起作用)。 如果此代码块重复n次,则需要通过应用Extract方法删除重复
您指出的重构是为了替换反复出现的切换情况。。如果您的示例中的语句。记住“最简单有效的事情”。。这意味着完成这项工作所需的类和方法的数量最少。在这种情况下,进行涉及多态性的重构可能有些过火(取决于您可能从多态性中获得的其他优势)。在本例中,添加一个简单的重载,该重载封装了要调用的
RunTableInfoCommand()
逻辑
由于RunTableInfoCommand()
,internalTableNumber
和internalTableName
似乎都是memb
private string RunTableInfoCommand( TableInfoEnum infoEnum)
{
if (this.internalTableNumber == null) {
return this.RunTableInfoCommand( internalTableName, infoEnum);
}
return this.RunTableInfoCommand( internalTableNumber.Value, infoEnum);
}
returnValue = this.RunTableInfoCommand( TableInfoEnum.TAB_INFO_NUM);
// or whatever enum is appropriate
(internalTableNumber == null) ==>
internalTableName else internalTableNumber.Value
public int Number
{
get
{
return iTable.RunTableInfoCommand(TableInfoEnum.TAB_INFO_NUM);
}
}