这个问题可能很简单,但是我想听听我们的代码有什么缺点。

因此,我们有一个简单的实现和接口:

public interface ISettings
{
    bool IsOnline { get; set; }
}

public class Settings : ISettings
{
    public bool IsOnline { get; set; }
}
该属性显示应用程序状态,并在许多情况下使用。在我们这里的界面是实现不同平台的设置所必需的。

我的同事坚持要实现一个附加属性:拥有这样的附加属性只是为了方便阅读代码的一种好习惯?

评论

当您忘记同时设置两个属性时,这将浪费大量的精力来维护两个属性,并且会引发将来的错误。
我不认为我会将此称为“互斥”,至少从界面的角度来看不是这样。

我会尽量避免使用“负”名称,因为它们经常会导致双重否定,从而引起混乱。

您不应具有两个描述对象同一方面的读写属性。我会按照@palacsint的建议去做。如果认为有必要,您始终可以添加诸如IsOnline之类的只读属性,它们仅检查status属性(或使用扩展方法)。

旁注,在这里投票到底有什么用?保持社区状态!

#1 楼

我认为同时拥有这两种特性实际上是有害的。如果只有一个属性,那么很清楚这意味着什么:设置可以在线或不在线。

但是当您有两个属性(并且不知道它们的实现)时,您就会开始想知道:是否有第三种情况?两个属性都可以是true还是false都?

好的文档可以回答所有这些问题,但是如果从一开始就很清楚就不必解释,那总是更好。

评论


\ $ \ begingroup \ $
+1指出第三种情况的可能性。如果下一个阅读您的代码的人甚至想知道这个问题,那么应该重写该代码!
\ $ \ endgroup \ $
– Shivsky
13-10-16在14:06

\ $ \ begingroup \ $
这是一个很好的观点!原始问题的明显答案是(在我看来)您绝对不能同时拥有IsOnline和IsOffline。但是,我对此没有真正的动机,只是觉得很不对劲。
\ $ \ endgroup \ $
–博伊西
13-10-19在7:36

\ $ \ begingroup \ $
如果IsOffLine没有设置员,将有助于减轻潜在的混乱。然后,进一步进行诸如“ Alias for!IsOnLine”之类的工具提示。
\ $ \ endgroup \ $
– radarbob
2014年2月21日,下午2:35

#2 楼

简要说明一下:带有StatusConnectionStatus值的ONLINE(或OFFLINE)枚举在此处更易读。

评论


\ $ \ begingroup \ $
+1这允许扩展其他状态,例如错误状态或过渡状态,例如“正在连接”
\ $ \ endgroup \ $
– deepee1
13-10-16在14:40

\ $ \ begingroup \ $
如果有人坚持要拥有更特定的只读属性,例如公共布尔IsConnected {get {return this.Status == ConnectionStatus.Connected; }。在任何情况下,我都不会创建两个单独的读写属性,这些属性只能相互取反。
\ $ \ endgroup \ $
– Mike Strobel
13-10-16在16:01



\ $ \ begingroup \ $
这个这个。具有两个值的枚举不是布尔值,应这样区分。
\ $ \ endgroup \ $
–琼·普迪(Jon Purdy)
2013年10月17日在2:17

\ $ \ begingroup \ $
我想说的是:布尔值不是具有两个值的枚举,因此不应实现为一个。
\ $ \ endgroup \ $
– jwg
13-10-17在9:51

\ $ \ begingroup \ $
@JonPurdy,我明白您的意思。但是我认为您是错误的,布尔值不是具有两个值的枚举。将枚举扩展为具有第三值是有意义的,将布尔值扩展为具有第三值是众所周知的荒谬的错误。将两个枚举数相乘或相乘得到第三个枚举是毫无意义的,而将两个布尔数相加或相乘是根本的。 if ... else不是switch ... case的特殊情况。
\ $ \ endgroup \ $
– jwg
13-10-20在6:05



#3 楼

如果同时实现这两个字段,则几乎必须保证它们的余生将始终保持一致,即IsOnline ==!IsOffline在任何时间点永远是永远有效的。 >可以吗?

如果有人也扩展您的课程并决定“扩展”逻辑该怎么办。现在是设置的子类型,可以在任何可以使用的地方使用?

如果几年后某人认为他们需要第三种状态,该怎么办:“触发了联机但尚未确认”,而不是适当地重新设计代码,而是决定对其进行调整,以使IsOffline短时间内== IsOnline == false?

如果您的代码在多线程环境中使用怎么办?如果一个线程将IsOnline设置为某个值,而另一个线程同时读取IsOffline?我能保证原子性,从而永远保证线程安全吗?

评论


\ $ \ begingroup \ $
那么不要将属性虚拟化吗?
\ $ \ endgroup \ $
– jwg
13-10-17在14:43

\ $ \ begingroup \ $
我认为继承不是问题,因为属性不是虚拟的。因此,派生类中的两个属性与原始属性无关(除非它们具有相同的名称)。
\ $ \ endgroup \ $
– svick
13-10-18在16:43

#4 楼

我会避免其他财产。完全没有必要。

包括ChrisWue的答案所建议的好处是可以提高可读性(甚至稍有提高)。除此之外,它没有任何优势可以弥补svick所建议的混乱(如果这将对未来的开发人员造成困扰,这是一个真正的考虑因素)。

布尔值可以是true或false(它已经适合两种情况)。仅通过创建一个否定版本就破坏了布尔的用途。

#5 楼

如果就业务逻辑而言,“离线”实际上只是一个“非在线”(很可能是),则该方法是多余的。

但是,创建与外观乍看起来并没有做任何事情,但可以充当占位符以更好地指示测试-并且在基础逻辑稍后发生更改时成为扩展的单个点。例如,假设我们有一个方法isAdminUser(),我们知道什么是“管理员用户没有化身”,因此,代替: br />
if (!isAdminUser()) {
   paintAvatar();
}


您以后可以选择扩展hasAvatar()的逻辑-也许头像变得可选,或者管理员用户在某些情况下可以拥有头像?

现在以上这个例子很简单,让我们回到isOnline / isOffline。如果isOffline仅是“不在线”,则可以。但是,如果实际上意味着您可以拥有“已认证用户”或“匿名”,则没人会说您可以轻松拥有isAuthenticated()isAnonymous()这两种方法,因为稍后您可以将isAuthenticated()分解为多种方法,而isAnonymous()将继续满足其目的,即代码专门针对匿名访问块。

#6 楼

是的,添加这样的属性可能是有益的:




在某种情况下测试阳性结果通常会使它更容易阅读,尤其是在这种情况下比较复杂。例如,

if (!IsOnline || ForceReset)
{
    TryReconnect();
}


vs

if (IsOffline || ForceReset)
{
    TryReconnect();
}


高度取决于谁读取代码以及如何读取规范(它存在)被写。如果规范说:如果系统离线或强制重设,请尝试重新连接,则第二个版本比第一个版本更容易连接到规范。例如,WPF)则具有第二个属性可能很有价值。通常,通过将IsEnabled属性设置为false来完成禁用用户控件之类的操作。现在想象一下,如果系统处于脱机状态,则需要启用一个按钮。如果存在IsOffline属性,绑定起来就容易得多。它的行为符合预期),因此请不要盲目地在模型中添加否定版本的布尔属性。当同时测试否定版本和非否定版本时,我会这样做。

评论


\ $ \ begingroup \ $
在WPF中进行绑定时,创建一个取反值的IValueConverter非常容易。但是我想在视图模型中同时拥有这两个属性是有意义的。
\ $ \ endgroup \ $
– svick
13-10-16在8:24

\ $ \ begingroup \ $
只有当这两个属性都是只读的并且对由另一个属性(例如“ ConnectionStatus”)控制的某些状态进行的简单解释时,才具有两个属性。甚至只有一个是只读的,而只有一个是可读写的也是奇怪的,因为除了结果求反外,它们在功能上是等效的,因此选择可写是任意的。而且,正如@svick所说,如果您的框架支持简单的值转换器,那么数据绑定将变得微不足道。
\ $ \ endgroup \ $
– Mike Strobel
13-10-16在16:14



\ $ \ begingroup \ $
当您已有转换器时,它会变得更加烦人,因为您绑定到了非布尔值属性(如Visibility)。有解决方法,但他们总是感到笨拙。
\ $ \ endgroup \ $
– ChristWue
13-10-16在20:43

\ $ \ begingroup \ $
+1表示@ Mark,-1表示此答案。这绝对是WTF。
\ $ \ endgroup \ $
– BlueRaja-Danny Pflughoeft
13-10-16在22:21

#7 楼

正如@palacsint提到的,我将创建一个Status属性,但是我还将创建一个只读的布尔型getter:
同时使用一个Setter拥有一个Status可以消除使用两个可写IsOnline IsOffline属性所具有的线程安全性问题。

#8 楼

我同意这个问题的其他答案,特别是palacsint的答案,但觉得它们没有集中在我认为最重要的方面:您在谈论接口。确保您定义的内容清晰明确-如果您提供两个属性,那么INTERFACE的使用者无法确保它们是互斥的。即使您证明他们应该实现,也可以很容易地忽略该实现或有一个错误,而事实并非如此。私有化并作为对对方的否定,一个人可能说没有伤害也没有犯规。

但是,一个接口应该有多个实现,并且所有需要实现的就是实现所需的结构,而不是以特定的方式实现。引入这种歧义不会改善界面。

#9 楼

您可以使用MixIn模式来做到这一点。这将是方法而不是属性,但希望这对您而言不是世界末日。将此静态类添加到与ISettings接口相同的名称空间中的某个位置: ”,而无需亲自实施。