我不确定这里是否应该使用某种模式,但情况如下:
我有许多实现接口的具体类:
public interface IPerformAction
{
bool ShouldPerformAction();
void PerformAction();
}
我有另一个类来检查输入以确定是否应该执行ShouldPerformAction。问题是新检查会相当频繁地添加。检查类的接口定义如下:
public interface IShouldPerformActionChecker
{
bool CheckA(string a);
bool CheckB(string b);
bool CheckC(int c);
// etc...
}
最后,我目前有具体的类使用特定于该具体类的数据调用每个检查器方法:
public class ConcreteClass : IPerformAction
{
public IShouldPerformActionCheck ShouldPerformActionChecker { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public int Property3 { get; set; }
public bool ShouldPerformAction()
{
return
ShouldPerformActionChecker.CheckA(this.Property1) ||
ShouldPerformActionChecker.CheckB(this.Property2) ||
ShouldPerformActionChecker.CheckC(this.Property3);
}
public void PerformAction()
{
// do something class specific
}
}
现在每次添加新检查时,我都必须重构具体类以包含新检查。每个具体类都将不同的属性传递给检查方法,因此具体类的子类不是一个选项。关于如何以更清洁的方式实施这一点的任何想法?
答案 0 :(得分:3)
让我们退后一步 - 为什么你首先使用接口?可以在IShouldPerformActionCheck
的多个实现之间共享IPerformAction
的单个实现吗?似乎答案是否定的,因为ICheck必须知道Action上的特定于实现的属性(Property1,Property2,Property3)才能执行检查。因此,IAction和ICheck之间的关系需要比IAction合同可以提供给ICheck的更多信息。看来你的Check类应该基于与他们检查的特定动作类型相关的具体实现,例如:
abstract class CheckConcreteClass
{
abstract void Check(ConcreteClass concreteInstance);
}
答案 1 :(得分:2)
“CheckA”,“CheckB”等名称,大概是为避免暴露机密信息而选择的,也会混淆类之间关系的性质,所以我不得不将它放在一边。
然而,这几乎是double dispatch,除了您正在执行中间对象的转换。
编辑:尝试“按书”播放双重调度模式,而不是在调度中分解对象。为此,您需要以下内容:
public interface IPerformAction
{
bool ShouldPerformAction(IShouldPerformActionChecker checker);
void PerformAction();
}
public interface IShouldPerformActionChecker
{
bool CheckShouldPerformAction(FloorWax toCheck);
bool CheckShouldPerformAction(DessertTopping toCheck);
// etc...
}
public class FloorWax : IPerformAction
{
public string Fragrance { get; set; }
// Note that the text of this method is identical in each concrete class,
// but compiles to call a different overload of CheckShouldPerformAction.
public bool ShouldPerformAction(IShouldPerformActionChecker checker)
{
return checker.CheckShouldPerformAction(this);
}
}
public class DessertTopping: IPerformAction
{
public string Flavor { get; set; }
// Note that the text of this method is identical in each concrete class,
// but compiles to call a different overload of CheckShouldPerformAction.
public bool ShouldPerformAction(IShouldPerformActionChecker checker)
{
return checker.CheckShouldPerformAction(this);
}
}
public class ShimmerApplicationChecker : IShouldPerformActionChecker
{
// handles binding of FloorWax class to required checks
public bool CheckShouldPerformAction(FloorWax toCheck)
{
return CheckAroma(toCheck.Fragrance);
}
// handles binding of DessertTopping class to required checks
public bool CheckShouldPerformAction(DessertTopping toCheck);
{
return CheckAroma(toCheck.Flavor);
}
// some concrete check
private bool CheckAroma(string aroma)
{
return aroma.Contains("chocolate");
}
}
答案 2 :(得分:1)
您可以将检查合并到一个采用对象的通用方法中:
public interface IShouldPerformActionChecker
{
bool Check(object o);
}
然后在具体类中列出这些检查:
public List<IShouldPerformActionCheck> ShouldPerformActionChecker { get; set; }
类型安全性较低,但更灵活。
您可以使用Predicate<T>委托,而不是使用IShouldPerformActionCheck
,这与大致完全相同。
答案 3 :(得分:0)
当你创建一个新的CheckN
时,你将不得不在每个具体的检查器类中实现它,不是吗?
或者您是在谈论重构IPerformActions以实际调用该支票?
为什么不只有一个CheckAll
来调用一切?
答案 4 :(得分:0)
不是让具体类尝试检查是否应该执行操作,而是可能有一种更易于维护的方法来安排这些对象。
如果检查器实际实现了IPerformAction,并且有一个IPerformAction成员,如果应该执行该操作,它会怎么样?该成员可以是链中的另一个检查者,或者如果所有标准都已通过则执行操作的实际类?
要做到这一点,可能需要稍微重构,以便执行操作的逻辑包含在一个类中,而要使用的特定数据在另一个类中(类似于Command模式),以便跳棋可以完成他们的工作。
通过这种方式,您可以轻松添加另一个验证规则,只需将其放入导致最终操作的对象的“链”中即可。
答案 5 :(得分:0)
您可以尝试这样的事情:
List<IShouldPerformActionChecker> checkers = new List<IShouldPerformActionChecker>();
//... add in each checker to try
foreach(ConcreteClass objectToCheck in checkset) {
bool isGood = true;
foreach(IShouldPerformActionChecker checker in checkers) {
isGood &= checker.DoCheck(objectToCheck.Property);
if (!isGood) { break; }
}
//handle failed check here
}