3

我希望能够使用这种代码实例化我的应用程序中的任何对象:

SmartForm smartForm = SmartForm.Create("id = 23");
Customer customer = Customer.Create("id = 222");

我现在正在讨论如果该对象不存在 Create() 应该返回什么。

  • 如果 Create() 返回一个空对象,那么这是一种“空模式”,我仍然可以在我的应用程序中传递该对象并调用它的方法,这使得使用此模型进行编程变得方便和容易

  • 如果 Create() 返回null,那么我需要在每次实例化后检查对象是否等于 null ,这使得编程有点乏味但更明确。这样做的一个问题是,如果您忘记检查 null,您的应用程序可能会在您不知道自己没有检查 null 的情况下工作很长时间,然后突然中断

  • 如果 Create()抛出异常,它基本上与返回 null 相同,但通过让您为每个实例化创建一个 try、next、finally 块,使编程更加乏味,但是您可以抛出各种类型的异常(您可以) t 与 null 解决方案)可能会冒泡,以便您可以更明确地处理 UI 上的深层错误,所以我认为这是最强大的解决方案,尽管会产生 try/catch 代码膨胀

所以这似乎是一个轻盈/稳健的权衡有没有人有过这样的决策经验?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestFactory234.Models
{
    public class SmartForm : Item
    {
        public string IdCode { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public int LabelWidth { get; set; }

        public SmartForm() { }

        private SmartForm(string loadCode)
        {
            _loadCode = loadCode;
            TryToInstantiateFromDatabase();
        }

        public static SmartForm Create(string loadCode)
        {
            SmartForm smartForm = new SmartForm(loadCode);

            if (!smartForm.IsEmpty())
            {
                return smartForm;
            }
            else
            {
                return null;
            }
        }
    }
}
4

6 回答 6

6

这取决于 - 如果它失败是因为某些事情肯定是错误的,那么异常会使编程更容易- 你不会在每个调用周围写一个 try/catch,你只是让异常冒泡。将其与检查空/空白返回值然后抛出异常进行比较。

这听起来像是使用的正确时间ArgumentException,IMO。

如果您发现自己在创建 try/catch “膨胀”,请查看为什么您确实需要捕获异常而不是让它们冒泡。

于 2009-06-10T13:26:27.040 回答
2

如果它返回一个空白对象,那么您将继续假设它是有效的 - 或者必须进行某种精心测试以查看它是否为空白。如果它返回 null,您将始终需要检查 null (也许这很好)。我宁愿它抛出一个异常——假设你的代码被设计成不应该发生这种情况。如果这是正常情况,那么 null 可能是更好的选择。

于 2009-06-10T13:24:36.500 回答
2

当默认行为是创建实例时,异常行为是创建失败 -> 异常

你会用 EmptyObject 做什么?你说你仍然可以传递它——这真的有意义吗?当您调用它们时,这些方法会做什么?

也许您应该实现第二个TryCreate()方法。

我会实现异常变体,但这取决于您需要的行为。

于 2009-06-10T13:26:01.410 回答
1

您的示例代码调用了“尝试从 DB 加载”方法,并且 Create 约定看起来很像Castle ActiveRecord对象。为什么不将 Get/Create 数据库操作分开,让框架完成工作并依赖它们的约定?

[ActiveRecord("Forms")]
public class SmartForm : Item
{
    [PrimaryKey("Id")]
    public string IdCode { get; set; }
    [Property]
    public string Title { get; set; }
    [Property]
    public string Description { get; set; }
    [Property]
    public int LabelWidth { get; set; }
}

你得到/创建这样的实例

SmartForm entity = ActiveRecordMediator<SmartForm>.Find(1);
SmartForm otherEntity = ActiveRecordMediator<SmartForm>.FindFirst(/* criteria */);

还有很多其他方法可用于查找实例。我想您会发现 ActiveRecord关于抛出异常、返回 null 或在集合的情况下为空集合的默认值非常一致且实现得很好。

于 2009-06-10T13:41:17.557 回答
0

如果你正在创建一个表单工厂,你最好传递一个枚举而不是一个字符串(当然,除非这代表一个插件架构)。

于 2009-06-10T13:25:42.207 回答
0

如果可以预见创建可能会失败,但很多应用程序代码都希望它能够工作,那么您真的应该实现两个版本的创建方法,一个应该成功或抛出异常,另一个应该应该通过某种方式指示预期的失败,而不是抛出异常,并且只为调用者可能没有预料到的失败抛出异常(例如 CpuIsOnFireException)。执行此操作的常见模式是让 TryCreate 方法返回一个指示成功的布尔值,将创建的参数存储到 by-ref 参数。我真的不喜欢这种模式,因为它没有提供任何指示除了通过失败状态之外的任何方法(即没有关于它失败的原因)。我认为“尝试”可能会更好 函数返回新事物或 null,但有一个 by-ref 参数指示失败的原因。请注意,这种方法将允许更好地使用隐式类型(例如 C# 中的“var”关键字)。

于 2011-03-22T20:09:04.590 回答