5 回答
代码重复是指块、语句甚至公共成员声明的分组的显着重复。它不是指语言关键字、标识符、模式等的重复。否则,您将无法实现多态性。
您提供的示例并没有真正演示开放/封闭原则,因为您还没有演示如何在不修改的情况下扩展给定类的行为。Open/Closed 原则是关于每次需要变体行为时创建新类。这可以通过使用继承和模板方法模式来实现(即在基类中调用抽象或虚拟方法,这些方法在子类中被覆盖以实现所需/新的行为),但更常见的是使用使用策略模式的组合来演示(即将变体行为封装在类中并将其传递给封闭类型,以用于确定实现的整体行为)。
从您的示例中,您似乎更多地考虑尝试通过继承来实现 OCP,但是从基本报告格式化程序开始建立具有子类型的接口以指示给定报告的不同类型的格式实际上是一个好的开始通过组合显示 OCP。使用基于组合的方法演示 OCP 需要一个使用格式化程序的类……比如说 ReportWriter。
public class ReportWriter : IReportWriter
{
Write(IReportData data, IReportFormatter reportFormatter)
{
// ...
var formattedStream = reportFormatter.Format(data, stream);
// ...
}
}
只是为了演示,我对我们的新格式化程序的行为做了一些假设,所以不要过分关注那部分。需要关注的是 ReportWriter 通过允许传入新的格式化程序而对扩展开放,从而影响报告的最终编写方式,但对实现这种新行为所需的代码修改(即 if 语句的存在,switch报表等多种方式实现格式化)。
Open/Closed 原则不仅不会导致代码重复,当通过使用组合而不是继承来实现时,它实际上可以帮助减少重复。如果在创建继承层次结构或策略类的过程中发生真正的代码重复,那么这表明存在与它可能存在于您尝试实现 OCP 的上下文中这一事实无关的分解问题。
你所拥有的对我来说看起来非常好。您没有修改 ReportFormatter,而是对其进行了扩展。
像这样的事情可以通过更好的方法设计来解决。请考虑以下内容:
namespace SOLIDPrincibles
{
public class ReportFormatter {
public virtual void FormatReport(String size) {
Console.WriteLine("Formatting Report for " + size + " ....");
}
}
public class TabloidReportFormatter : ReportFormatter {
public override void FormatReport() {
super.FormatReport("11 X 17");
}
}
}
我认为按照这些思路进行设计将是消除重复代码的最佳方法。
我自己实现了一个自定义格式的报告系统,我想说这种方法已经是错误的了。
当您将格式作为参数提供给构造函数时,为什么每种格式都有一个格式化程序类?格式化程序类 ctor(甚至 ReportFormatter 类的静态格式化方法)应该有一个报告和一个格式描述作为参数,并相应地格式化报告。
每种格式都不需要一个类。
像这样的东西应该工作。
namespace SOLIDPrinciples
{
public class ReportFormatter {
public virtual void FormatReport() = 0;
}
public class VariableSizeReportFormatter : ReportFormatter {
public void SetSize(String size);
public override void FormatReport() {
Console.WriteLine("implement generic layout routines");
}
}
public class TabloidReportFormatter : VariableSizeReportFormatter {
public override void FormatReport() {
// currently, we just do a tweaked version of generic layout ..
SetSize("11x7");
Super.Format();
Console.WriteLine("RemoveThatColumnWeDontWant");
}
}
}
这意味着:
- ReportFormatter 的客户端不需要更改(假设其他地方有一些处理设置的机制)。
- 可以添加对通用格式功能的改进以改进所有报告,因此没有重复的代码
- 您只需要在某些特定情况下更好地工作,您就可以进行更改
这是关键的第三点:您可以说“原则上,如果注释使行太大而无法容纳,智能布局例程应该知道从日期中删除年份”。但是在实践中实施这种改变可能是一场噩梦,如果这意味着另一个报告出现错误,那么你必须改变它的工作逻辑,然后重新测试系统中的每个报告布局......