您好,感谢您的帮助。
使用.Net 3.5 C#;
假设我有大约10种方法都遵循相同的模式
以3为例:
public Customer CreateCustomer(Customer c) { .. }
public Car CreateCar(Car c) { .. }
public Planet CreatePlanet(Planet p) { ..}
每种方法的内部逻辑具有完全相同的模式。
IE:
public Customer CreateCustomer(Customer c)
{
Log.BeginRequest(c, ActionType.Create);
Validate(customer);
WebService.Send(Convert(c));
Log.EndRequest(c, ActionType.Create);
}
public Car CreateCar(Car c)
{
Log.BeginRequest(c, ActionType.Create);
Validate(c);
WebService.Send(Convert(c));
Log.EndRequest(c, ActionType.Create);
}
CreatePlanet和其他7种方法也是如此。
这些方法可以重写,它们都遵循相同的模式,我觉得我错过了一些东西......是否有另一层抽象可以衍生出来?
问题:如何重写以利用适当的架构模式?
谢谢, 史蒂文
答案 0 :(得分:7)
这似乎符合模板模式的情况。您可以使所有实体实现相同的接口/基础并对接口执行操作。
我假设唯一需要知道实际类型的部分是Validate()
。它可以通过两种方式解决:
使用基类抽象验证的示例 -
实体的基础,其中包含用于验证的创建和抽象定义的内部服务:
public abstract class EntityBase
{
protected abstract void Validate();
protected void Create(EntityBase c)
{
Log.BeginRequest(c, ActionType.Create);
c.Validate();
WebService.Send(Convert(c));
Log.EndRequest(c, ActionType.Create);
}
}
具有验证功能的具体实现者:
public class Customer : EntityBase
{
private int year;
public Customer(int year)
{
this.year = year;
}
public void CreateCustomer(Customer c)
{
Create(c);
}
protected override void Validate()
{
if (year < 1900)
{
throw new Exception("Too old");
}
}
}
我没有在原始代码中看到Create
返回的内容,因此我将其更改为无效以使示例清晰
答案 1 :(得分:2)
我认为您正在寻找generic method解决方案。
public T Create<T>(T t)
{
Log.BeginRequest(t, ActionType.Create);
Validate(t);
WebService.Send(Convert(t));
Log.EndRequest(t, ActionType.Create);
return t;
}
答案 2 :(得分:1)
是的,使用通用功能:
public T TrackInstantiation<T>(T entity)
{
Log.BeginRequest(entity, ActionType.Create);
Validate(entity);
WebService.Send(Convert(entity));
Log.EndRequest(entity, ActionType.Create);
// Don't you also need to return the thing to fulfill the method siugnature ?
return entity;
}
我更改了方法的名称,因为您不是在此方法中创建对象(您传入已创建的实例),您只是在验证,保留并记录它的创建。顺便说一句,为什么不在这里实际创建对象呢?然后,这将接近称为抽象工厂的模式。
你也可以使用界面做同样的事情。
public interface ICanBeTracked {/ * No methods * /}
修改要传递给此方法的每个类型,以便它们也实现此接口,然后只需编写方法
public ICanBeTracked TrackInstantiation(ICanBeTracked entity)
{
Log.BeginRequest(entity, ActionType.Create);
Validate(entity);
WebService.Send(Convert(entity));
Log.EndRequest(entity, ActionType.Create);
// Don't you also need to return the thing to fulfill the method siugnature ?
return entity;
}
...并使用输入参数类型为ICanBeTracked参考
对上述方法调用的三种方法中的每一种进行重载答案 3 :(得分:1)
public T Create<T>(T c)
{
Log.BeginRequest(c, ActionType.Create);
Validate(customer);
WebService.Send(Convert(c));
Log.EndRequest(c, ActionType.Create);
}
答案 4 :(得分:0)
您可以使用通用方法:
T Create<T>(T arg)
或者只是System.Object:
object Create(object arg);
{
Log.BeginRequest(arg, ActionType.Create);
Validate(arg);
WebService.Send(Convert(arg));
Log.EndRequest(arg, ActionType.Create);
return arg; //It must have a return
}
Car CreateCar(Car c)
{
return (Car)Create(c);
}
答案 5 :(得分:0)
如果类型不同或者您可以创建通用方法,则可以为这十种类型提取公共接口。
答案 6 :(得分:0)
我看到了一些模板功能的建议。这很好,但它并不能说明整个故事。我猜测问题的一部分是你的每一个Validate和Convert函数的工作方式都有所不同,这意味着一个简单的泛型函数可能不够用。
如果是这种情况,您有几个选择。一种是重载Validate / Convert函数,让类型系统的重载决策能够解决哪一个问题。另一个(这是首选)是使用之前推荐的模板模式,只是让每个类型实现一个通用接口。第三个选项是为每个方法要求函数的委托参数。您已经有前两个示例,所以这里是一个代码示例,说明如何编写接受委托的方法:
public T Create<T>(T c, Action<T> validate, Func<T, string> convert)
{
Log.BeginRequest(c, ActionType.Create);
validate(c);
WebService.Send(convert(c));
Log.EndRequest(c, ActionType.Create);
}
答案 7 :(得分:0)
您可以使用面向方面的编程来应用日志记录和验证。使用来自Microsoft Patterns&amp; Sons的PIAB(策略注入应用程序块)(企业库的一部分)。实践团队(假设配置已经到位)你最终会得到这样的结论:
[LogRequest(ActionType.Create)]
[DoValidate()]
public T Create<T>(T item)
{
WebService.Send(convert(item));
}
其中LogRequest是一个自定义属性,用于实例化新的ICallHandler,在其中记录请求的开始,调用getNext()
(将控制权发送到链中的下一个ICallHandler,或者如果这是最后一个链,将控制发送到被调用的方法),然后当控制返回到ICallHandler时,它将记录请求的结束。
验证可能由验证应用程序块处理,该块与PIAB无缝协作 或者你可以编写自己的验证处理程序
AOP可以大幅减少您需要的代码量,但请注意不要过度使用它。
您可以在此处阅读企业库:http://www.codeplex.com/entlib/