【问题标题】:Is having a lot of properties initiated at instantiation a good practice?在实例化时启动很多属性是一种好习惯吗?
【发布时间】:2019-05-05 20:42:58
【问题描述】:

我有一个具有很多属性的 Cart 类:

public class Cart
{
    public Customer Customer { get; set; }
    public Products Products { get; set; }
    public Payments Payments { get; set; }
    public DateTime TimeOfArrival { get; set; }
    //...and so on
}

每当我想实例化一个新的Cart 时,我都需要启动这些属性。其中一些是已知的(例如客户),另一些是未知的(例如产品和付款)。所以当我实例化一张新票时,这就是我最终做的事情:

Cart Cart = new Cart
                    {
                        // for know properties:
                        Customer = currentCustomer,
                        TimeOfArrival = DateTime.Now,

                        // for properties that are going to be filled later:
                        Products = new List<Product>(),
                        Payments = new List<Payment>(),

                        // ...and so on
                    };

这个解决方案显然有效,但在实例化时似乎非常庞大,而且在启动器中完成了很多工作,我认为这是一件坏事。

我这样做是对的还是在实例化时启动了很多属性不是一个好习惯?如果是这样,我应该怎么做?

提前致谢

【问题讨论】:

  • 你没有做错什么,这不是很多..
  • 本身没有错。事实上,为您的属性设置默认值是一个很好的做法。您可以使用 stackoverflow.com/questions/40730/… 缩短代码,这将消除初始化对象时重复代码行的需要
  • 为什么 Cart 类不能实例化 ctor 中的那些对象?消除了消费者为了使任何事情正常工作而这样做的需要。
  • @Aldert @Steve 感谢您的快速回答,实际上还有一些其他属性我没有让您幸免,但我相信它不会有太大变化。问题是构造函数不允许我在构造函数中将new List&lt;Thing&gt;() 设置为默认参数值。

标签: c# oop constructor


【解决方案1】:

是的,还有改进的余地。但要小心,很多取决于要求,基本上他们应该在很多情况下领先。这是一个品味问题。有些人比其他人更纯粹。

这取决于您的项目:它有多重要?它是一个副项目还是你的核心业务?

而且,是的,还有改进的余地;总是有......现在,明年,每次评论......等等。只是说:没有完美的设计。


现在,我强烈的偏见:)

您的设置代表了领域驱动设计中的典型案例。稍后我会发送链接。

通常,在域驱动设计中,您会尝试确定特定的业务功能/概念,并将其包装在最好是最具描述性的对象中。基本上,您的购物车是在正确的轨道上。

但是,购物车中似乎只有一点点领域知识。

特别是嵌套的复杂类型可能表明您正在跨越某些域边界。

例如:customer;它位于购物车内。客户可能又包含一个地址。 ...等等。

很明显,一个人的地址与购物车本身无关。

还有;支付。我不认为它通常绑定到购物车,可能更多绑定到订单。

关于产品;一个简短的描述和一个指向实际产品的链接就足够了。旁边当然是明显的价格和数量。

对于购物车,您可能需要考虑仅存储客户 ID,并在需要其他数据时获取客户。

总之,这是一个一般性的主题。最好的建议是;不要试图涉及太多复杂的类型,只在模型中放入只对特定“事物”有意义的事物

【讨论】:

  • 感谢您非常鼓舞人心的回答。我实际上正在尝试为我自己的(非常小的)企业制作一个 UWP 注册应用程序,尽管它不必非常复杂。
  • 酷 :-) ... 奖励:如果您是 UWP,绝对值得检查 MVVM 模式 :)
  • 我已经开始了!来自数据科学,我觉得我在 oop 中发现了一个全新的世界。
【解决方案2】:

使用构造函数:

public class Cart
{
    // shorthand constructor, only 1 setting, else use a normal function style constructor
    public Cart (Customer cust) => Customer = cust;

    public Customer Customer { get; set; }
    public Products Products { get; set; } = new List<Product>();
    public Payments Payments { get; set; } = new List<Payment>();
    public DateTime TimeOfArrival { get; set; } = DateTime.Now;
    //...and so on
}

var cart = new Cart( my_customer_instance );  // all thats needs to be done

如果您只为自己的业务开发一些东西,这比Lazy&lt;...&gt; 方法更容易。如果您有昂贵的东西要创建,而这些东西可能根本不需要,也可能根本不需要。空列表不会花费您太多 - 如果您真的担心,您甚至可以使用 0 个元素创建它们(如果您“喂”它们,它们会增加内部缓冲区)。

最大的优势是您不必关心如果您需要 new Cart(customer) 该怎么做 - 该类自己处理初始化。

【讨论】:

  • 我肯定会使用这种方法,我不知道这种定义属性默认值的方法。
【解决方案3】:

如果您担心预先初始化属性的成本(在这种情况下,这看起来不成问题),那么您可以使用Lazy&lt;T&gt; 在需要时方便地实例化属性。

例如

private Lazy<List<Product>> products;
constructor() {
   products = new Lazy<List<Product>>(()=>new List<Product>());
} 
public List<Product> Products => products.Value;

对于像列表这样的东西,这很愚蠢,但对于更昂贵的初始化,Lazy&lt;T&gt; 可能很有用。

【讨论】:

  • 不是我想要的,但很高兴知道,谢谢!实际上我的 Product 类很重,所以将来可能会有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多