我有一段与此类似的代码:
public bool DoMyThings(EnumRootAction root, EnumChildAction child){
switch(root){
case EnumRootAction.Type1:
switch(child){
case EnumChildAction.Ac1:
// DO something
break;
case EnumChildAction.Ac2:
// DO something
break;
default: // child is not child of type root
return false;
}
break;
case EnumRootAction.Type2:
switch(child){
case EnumChildAction.Ac1:
// DO something
break;
case EnumChildAction.Ac3:
// DO something
break;
default: // child is not child of type root
return false;
}
break;
... // etc...
default:
return false;
}
return true;
}
但是,我确实认为这是一个糟糕的代码...... :) ..."消费者"此服务不知道有效且可能传递错误的root / child的正确组合。
我想到了" spiting"它分为几种方法,例如:DoMyThingsForRootType1(EnumChildActionForType1 child)
,但从长远来看,在我的情况下这并不容易改变。我解释了原因:如果我的服务签名不断变化,我需要更新所有实时客户端的服务协议....更新源代码并再次部署....现在客户端可以简单地制作通过更改一些app.settings值手动更改这些更改。
此时我正在提供一张带有正确组合的单张纸,但这也是我眼中的垃圾。
也许我只是从一个角度看这个,不知怎的,我无法扩大我的视野...这就是为什么我想听听你们/ gals的一些反馈......
这有更好的设计模式吗? 至少某种方式告知服务的客户有效组合....
感谢。
答案 0 :(得分:0)
第一步可能是在每种情况下你都会调用一个方法。
case EnumRootAction.Type1:
switch(child){
case EnumChildAction.Ac1:
Type1_Ac1();
break;
第二步可能是您使用委托矩阵而不是函数。
delegate bool DoMyThingsAction();
DoMyThingsAction[,] doMyThings;
public void InitializeDoMyThings()
{
doMyThings = new DoMyThingsAction[10, 10]; // number of actions and type
doMyThings[0, 0] = Type1_Ac1;
// and so on
}
要调用它,您可以使用
doMyThings[(int)root, (int)child];
如果您不喜欢在doMyThings调用中使用强制转换为int,则可以使用不同的结构并覆盖索引器。
另一个选择是使用反射来获取方法(我不喜欢它)
public bool DoMyThings(EnumRootAction root, EnumChildAction child){
return GetType().GetMethod(string.Format("{0}_{1}", root, child).Invoke(this);
}
修改强>
查看您的程序,如果没有方法,则应返回false。
在矩阵的情况下,你可以在调用之前检查是否有函数,如果反映你可以检查GetMethod是否返回null。
答案 1 :(得分:0)
如果您可以使用接口或基类而不是枚举,则可以利用面向对象的功能来确定如何评估组合。这允许您以易于理解和易于维护的方式对root / child操作功能进行分组。然而,这有点啰嗦:
public interface IChildAction
{
}
public class ChildAction1 : IChildAction
{
}
public class ChildAction2 : IChildAction
{
}
public class ChildAction3 : IChildAction
{
}
public abstract class BaseRootAction
{
public virtual bool Process(ChildAction1 action)
{
return false;
}
public virtual bool Process(ChildAction2 action)
{
return false;
}
public virtual bool Process(ChildAction3 action)
{
return false;
}
}
public class RootAction1 : BaseRootAction
{
public override bool Process(ChildAction1 action)
{
Console.WriteLine("Root action 1, Child action 1");
return true;
}
public override bool Process(ChildAction2 action)
{
Console.WriteLine("Root action 1, Child action 2");
return true;
}
}
public class RootAction2 : BaseRootAction
{
public override bool Process(ChildAction1 action)
{
Console.WriteLine("Root action 2, Child action 1");
return true;
}
public override bool Process(ChildAction3 action)
{
Console.WriteLine("Root action 2, Child action 3");
return true;
}
}
public class RootAction3 : BaseRootAction
{
public override bool Process(ChildAction2 action)
{
Console.WriteLine("Root action 3, Child action 2");
return true;
}
}
public bool DoMyThings(BaseRootAction rootAction, IChildAction childAction)
{
return rootAction.Process((dynamic)childAction);
}
我还包括我的完整性测试方法:
private void Test()
{
List<BaseRootAction> rootActions = new List<BaseRootAction>() { new RootAction1(), new RootAction2(), new RootAction3()};
List<IChildAction> childActions = new List<IChildAction>() { new ChildAction1(), new ChildAction2(), new ChildAction3()};
foreach (BaseRootAction rootAction in rootActions)
{
foreach (IChildAction childAction in childActions)
{
bool result = DoMyThings(rootAction, childAction);
Console.WriteLine(String.Format("Processed '{0}' / '{1}': Result = {2}", rootAction.GetType().Name, childAction.GetType().Name, result));
}
}
}
如果您需要Enums,可以从它们派生动作类,但解决方案变得更加臃肿。
答案 2 :(得分:0)
您可以应用访客模式。您的ChildAction
是访问者,List<RootAction_Visitor> visitors = new List<>();
visitors[EnumRootAction.Type1] = new RootAction1_Visitor();
visitors[EnumRootAction.Type2] = new RootAction2_Visitor();
List<ChildAction_Element> elements = new List<>();
elements[EnumChildAction.Ac1] = new ChildAction1_Element();
elements[EnumChildAction.Ac2] = new ChildAction2_Element();
elements[EnumChildAction.Ac3] = new ChildAction3_Element();
public void doMyThing(EnumRootAction root, EnumChildAction child) {
elements[child].accept( visitors[root] );
}
//=======================================================================
// Visitors
abstract class RootAction_Visitor {
public void visit(ChildAction1_Element childAction) { /*.. reject by default ...*/ }
public void visit(ChildAction2_Element childAction) { /*.. reject by default ...*/ }
public void visit(ChildAction3_Element childAction) { /*.. reject by default ...*/ }
}
class RootAction1_Visitor : RootAction_Visitor {
public override void visit(ChildAction1_Element childAction) {
// ... do something
}
public override void visit(ChildAction2_Element childAction) {
// ... do something
}
}
class RootAction2_Visitor : RootAction_Visitor {
public override void visit(ChildAction1_Element childAction1) {
// ... do something
}
public override void visit(ChildAction3_Element childAction3) {
// ... do something
}
}
//=======================================================================
// Elements
interface ChildAction_Element {
void accept(RootAction_Visitor visitor);
}
class ChildAction1_Element : ChildAction_Element {
public void accept(RootAction_Visitor visitor) { visitor.visit(this); }
}
class ChildAction2_Element : ChildAction_Element {
public void accept(RootAction_Visitor visitor) { visitor.visit(this); }
}
class ChildAction3_Element : ChildAction_Element {
public void accept(RootAction_Visitor visitor) { visitor.visit(this); }
}
是元素。这是代码,注意OOP中的重载功能有多强大:
RootAction
因为您的客户端和服务器通过网络进行通信(进程间通信)。没有办法确保客户端发送的数据有效,我们需要验证数据并拒绝错误的请求。但是,您应该提供其他服务,以便客户在请求主服务之前知道哪些操作组合是正确的。
P / S:在ChildAction
和RootAction
之间进行选择,即来访者,这取决于他们的稳定程度。如果RootAction
s不稳定,即会出现新的Visitors
种类,那么它们应为input
。