是否有针对多条消息和成功/失败的通知模式的替代方案?
我有一个类 OperationResult,我用它来返回 Success
bool 值和“错误”消息列表。这些消息有时是意想不到的错误,但更多的是经常发生的普通情况。有时我们会返回一条错误消息,但有时我们会返回多条错误消息。我希望找到更好的方法。
这似乎或多或少是the Notification pattern advocated by Fowler .然后消费者对成功状态和错误做一些合理的事情,最常见的是向用户显示错误,但有时在非 fatal error 的情况下继续。
因此我有很多看起来像这样的服务方法(不是网络服务方法):
private ThingRepository _repository;
public OperationResult Update(MyThing thing)
{
var result = new OperationResult() { Success = true };
if (thing.Id == null) {
result.AddError("Could not find ID of the thing update.");
return result;
}
OtherThing original = _repository.GetOtherThing(thing.Id);
if (original == null) return result;
if (AnyPropertyDiffers(thing, original))
{
result.Merge(UpdateThing(thing, original));
}
if (result.Success) result.Merge(UpdateThingChildren(thing));
if (!result.HasChanges) return result;
OperationResult recalcResult = _repository.Recalculate(thing);
if (recalcResult.Success) return result;
result.AddErrors(recalcResult.Errors);
return result;
}
private OperationResult UpdateThing(MyThing ) {...}
private OperationResult UpdateThingChildren(MyThing) {...}
private bool AnyPropertyDiffers(MyThing, OtherThing) {...}
可以想象,UpdateThing
、UpdateThingChildren
和ThingRepository.Recalculate
都有类似的OperationResult
合并/操纵与其业务逻辑交错的代码。
是否有替代方法可以替代围绕我返回的对象进行的大量代码修改?我希望我的代码只关注业务逻辑,而不必特别关注如何操作 OperationResult
。
我希望代之以看起来像下面这样的代码,能够更好地表达其业务逻辑并减少消息处理的麻烦:
public ??? Update(MyThing thing, ???)
{
if (thing.Id == null) return ???;
OtherThing original = _repository.GetOtherThing(thing.originalId);
if (original == null) return ???;
if (AnyPropertyDiffers(thing, original))
{
UpdateThing(thing, original));
}
UpdateThingChildren(thing);
_repository.Recalculate(thing);
return ???;
}
有什么想法吗?
注意:抛出异常在这里并不合适,因为消息并非异常。
最佳答案
我认为这是函数式编程可以提供帮助的情况,所以我会尝试使用 package将一些 F#
功能移植到 C#
using Optional;
因为我们要管理异常
using Optional.Unsafe;
此时我们可以引入一个助手,来执行典型的功能性“monad chaining”
public static class Wrap<Tin, Tout>
{
public static Option<Tout, Exception> Chain(Tin input, Func<Tin, Tout> f)
{
try
{
return Option.Some<Tout,Exception>(f(input));
}
catch (Exception exc)
{
return Option.None<Tout, Exception>(exc);
}
}
public static Option<Tout, Exception> TryChain(Option<Tin, Exception> input, Func<Tin, Tout> f)
{
return input.Match(
some: value => Chain(value, f),
none: exc => Option.None<Tout, Exception>(exc)
);
}
}
现在,假设我们有以下可能引发异常的更新:
Type2 Update1 (Type1 t)
{
var r = new Type2();
// can throw exceptions
return r;
}
Type3 Update2(Type2 t)
{
var r = new Type3();
// can throw exceptions
return r;
}
Type4 Update3(Type3 t)
{
var r = new Type4();
// can throw exceptions
return r;
}
我们将能够在 Happy Path 之后编写一个逻辑流程
Option<Type4, Exception> HappyPath(Option<Type1, Exception> t1)
{
var t2 = Wrap<Type1,Type2>.TryChain(t1, Update1);
var t3 = Wrap<Type2, Type3>.TryChain(t2, Update2);
return Wrap<Type3, Type4>.TryChain(t3, Update3);
}
最后,有了一个扩展类,比如
public static class Extensions {
public static Option<Type2, Exception> TryChain(this Option<Type1, Exception> input, Func<Type1, Type2> f)
{
return Wrap<Type1, Type2>.TryChain(input, f);
}
public static Option<Type3, Exception> TryChain(this Option<Type2, Exception> input, Func<Type2, Type3> f)
{
return Wrap<Type2, Type3>.TryChain(input, f);
}
public static Option<Type4, Exception> TryChain(this Option<Type3, Exception> input, Func<Type3, Type4> f)
{
return Wrap<Type3, Type4>.TryChain(input, f);
}
}
快乐之路可以写成美丽的形式
Option<Type4, Exception> HappyPath(Option<Type1, Exception> t1)
{
var t2 = t1.TryChain(Update1);
var t3 = t2.TryChain(Update2);
return t3.TryChain(Update3);
}
关于c# - 对于多条消息和成功/失败,是否有替代通知模式的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40404327/