因此,我们有一个简单的实现和接口:
public interface ISettings
{
bool IsOnline { get; set; }
}
public class Settings : ISettings
{
public bool IsOnline { get; set; }
}
该属性显示应用程序状态,并在许多情况下使用。在我们这里的界面是实现不同平台的设置所必需的。我的同事坚持要实现一个附加属性:拥有这样的附加属性只是为了方便阅读代码的一种好习惯?
#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 楼
简要说明一下:带有Status
和ConnectionStatus
值的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的使用者无法确保它们是互斥的。即使您证明他们应该实现,也可以很容易地忽略该实现或有一个错误,而事实并非如此。私有化并作为对对方的否定,一个人可能说没有伤害也没有犯规。但是,一个接口应该有多个实现,并且所有需要实现的就是实现所需的结构,而不是以特定的方式实现。引入这种歧义不会改善界面。
评论
当您忘记同时设置两个属性时,这将浪费大量的精力来维护两个属性,并且会引发将来的错误。我不认为我会将此称为“互斥”,至少从界面的角度来看不是这样。
我会尽量避免使用“负”名称,因为它们经常会导致双重否定,从而引起混乱。
您不应具有两个描述对象同一方面的读写属性。我会按照@palacsint的建议去做。如果认为有必要,您始终可以添加诸如IsOnline之类的只读属性,它们仅检查status属性(或使用扩展方法)。
旁注,在这里投票到底有什么用?保持社区状态!