长期以来,DRY(请勿重复自己)的原理对于每个人都是显而易见的,并且受到许多程序员的喜爱。 许多人都认为复制/粘贴一点都不酷。 在本文中,我想举一个例子,说明在工业编程中何时使用“复制/粘贴”更为合适,并有助于实现SOLID中的“开闭”原理。
让我提醒您,开放封闭原则鼓励程序员设计类,以便它们可以扩展,但同时也可以修改。 仅当在类中检测到错误时才允许修改类。 如果要添加功能,则该原理要求创建一个新类,并使用同一接口的继承或实现。
例如,有一个包裹管理系统。 假设,除了简单的程序包之外,紧急的任务还增加了创建功能。
我们有一个Parcel类,描述了常规包裹的工作方式:
public interface IParcel { string Barcode {get; set;} } public class Parcel: IParcel { public string Barcode {get; set;} }
将一个字段简单地添加到旧的Parcel类和IParcel接口中是很诱人的:
public interface IParcel { string Barcode {get; set;} bool IsUrgent {get; set;} } public class Parcel: IParcel { public string Barcode {get; set;} public bool IsUrgent {get; set;} }
但是,此类代码不应通过CodeReview! 严格且经验丰富的代码检查器应返回以下说明:“这种实现违反了开放式原则。”
最好创建一个新的UrgentParcel类,并且您无需更改接口或Parcel类。 类和接口文件将保持不变:
public class UrgentParcel: IParcel { public string Barcode {get; set;} }
这将遵循开放式原则,并且此类代码将不会在CodeReview中收到注释。
现在让我们回到DRY以及它难以实现开放式封闭原则的方式。
想象一下,在包裹类中,我们有“包裹的状态”字段和一些用于更改此状态的逻辑:
public class Parcel: IParcel { public string Barcode {get; set;}
是否需要将此逻辑复制到UrgentParcel类? DRY原则绝非如此。 最好是UrgentParcel类直接继承自Parcel类,这样可以解决问题,而不必将ArrivedToRecipient方法的主体复制/粘贴到UrgentParcel类。
但是,如果您不复制代码而是继承代码,则对Parcel类中的ArrivedToRecipient方法所做的更改将立即导致UrgentParcel类的行为发生更改,这将违反开放式封闭原则。 这确实是一种违反,因为带有紧急包裹的任务(执行UrgentParcel类)已经交付,测试并且因此“在战斗中”工作。 因此,此逻辑在UrgentParcel.ArrivedToRecipient方法中实现并应用于紧急包裹,适合所有人,并且在其他类型的包裹的工作发生更改时也不应更改。 因此,Open-closed原则是专门设计用来保护系统,使其免受经验不足的初级程序员的攻击,这些初级程序员在解决任务时,像往常一样“直面”,但尚未意识到所有依赖关系,并且它们在一个地方的更改会影响许多其他功能区域。
通常,支持DRY的主要参数之一是以下事实:如果在ArrivedToRecipient方法中发现错误,则应将其复制到任何地方都将其修复。 因此,这只是不需要做的。 如果在使用常规程序包时在ArrivedToRecipient方法中发现错误,则必须更正常规程序包的工作。 但是没有人抱怨紧急包裹的工作,也许每个人都对紧急包裹的工作方式感到满意。
对于我也认为也是我自己的完美主义者,我建议您发表评论,使我们不要忘记所有复制该方法的地方,并提出一个问题:对于紧急包裹,此方法是否正确工作?
这是此类评论的示例:
public class Parcel: IParcel{ ...
社区对此问题的意见非常有趣。 预先感谢您的评论。