c# - 对于多条消息和成功/失败,是否有替代通知模式的方法?

标签 c# oop design-patterns return messages

是否有针对多条消息和成功/失败的通知模式的替代方案?

我有一个类 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) {...}

可以想象,UpdateThingUpdateThingChildrenThingRepository.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/

相关文章:

c# - 使用 selenium、Nunit、Selenium Grid、C#、webdriver/remote control 的自动浏览器测试

c# - 无法安全锁定 ConcurrentDictionary 的值

java - ANDROID Sqli 游标仅返回 1 行之后它给出空异常

php - 在类中包含来自外部 php 文件的方法

对相同类类型的 C++ 引用公开私有(private)成员

c++ - 如何在 Qt 中设计异步包装器返回值?

javascript - 如何使用 C# 或 JavaScript 等代码触发元素点击?

c# - 在这种情况下我可以避免反射(reflection)吗?

objective-c - 为什么使用字符串常量与枚举常量?

c++ - 常规迭代器(或类似的范围/ View 类)是否应该从 const_iterator 派生?