OCP(开放/封闭原则)是SOLID原则之一。这是说:
“软件实体应该是可以扩展的,但已经关闭以进行修改。”
我需要了解上述关于OCP的句子。当我开始阅读更多关于它的内容时,我发现它有意义且非常有用,但同时我注意到它会导致重复的代码。
如何将这样一个重要的原则“OCP”作为大规模代码重复实践的原因?
namespace SOLIDPrinciples
{
public class ReportFormatter {
public virtual void FormatReport() {
Console.WriteLine("Formatting Report for 8-1/2 X 11 ....");
}
}
public class TabloidReportFormatter : ReportFormatter {
public override void FormatReport() {
Console.WriteLine("Formatting Report for 11 X 17 ....");
}
}
}
我在这里遗漏了什么吗?有没有其他方法可以解释OCP?
答案 0 :(得分:4)
代码重复是指对常见成员声明的块,语句或甚至分组的重复重复。它并不是指语言关键字,标识符,模式等的重复。否则你将无法实现多态。
您提供的示例并未真正演示打开/关闭原则,因为您尚未演示如何在不进行修改的情况下扩展给定类的行为。开放/封闭原则是关于每次需要变体行为时创建新类。这可以使用继承以及模板方法模式来实现(即在基类中调用抽象或虚拟方法,这些方法在子类中被覆盖以实现期望/新行为),但是更经常使用策略模式使用组合来证明(即在类中封装变体行为并将其传递给闭合类型以用于确定所实现的整体行为。
从您的示例中,您似乎更多地考虑通过继承来实现OCP,但是从基础报告格式化程序开始,以建立具有子类型的接口以指示给定报告的不同类型的格式实际上是通过构图展示OCP的良好开端。使用基于组合的方法演示OCP所需要的是一个消耗格式化程序的类......比如ReportWriter。
public class ReportWriter : IReportWriter
{
Write(IReportData data, IReportFormatter reportFormatter)
{
// ...
var formattedStream = reportFormatter.Format(data, stream);
// ...
}
}
仅仅为了演示,我已经对我们的新格式化程序的行为做了一些假设,所以不要过分关注那部分。需要关注的是,ReportWriter可以通过允许传入新的格式化程序来进行扩展,从而影响报表的最终编写方式,但是为了修改实现这种新行为所需的代码而关闭(即if语句的存在,切换语句等实现多种格式化方式)。
开放/封闭原则不仅不会导致代码重复,当通过使用组合而不是继承实现它实际上可以帮助减少重复。如果在创建继承层次结构或策略类的过程中发生了真正的代码重复,则表明与您尝试实现OCP的上下文中可能存在的事实无关的因子问题。
答案 1 :(得分:0)
你看起来对我来说完全没问题。你没有修改ReportFormatter,你扩展了它。
答案 2 :(得分:0)
这样的事情可以通过更好的方法设计来解决。请考虑以下内容:
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");
}
}
}
我认为按照这些方式进行设计是消除重复代码的最好方法。
答案 3 :(得分:0)
自己实施了自定义格式报告系统后,我说这种方法已经错了。
为什么在将格式作为构造函数的参数时,每种格式都有一个格式化程序类?格式化程序类ctor(甚至是ReportFormatter类的静态格式方法)应该有一个报表和一个格式描述作为参数,并相应地格式化报表。
每种格式都不需要课程。
答案 4 :(得分:0)
这样的事情应该有效。
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");
}
}
}
这意味着:
这是关键的第三点:你可以说'原则上,如果评论使行太大而不适合,智能布局例程应该知道从日期开始减去年份'。但是在实践中实现这种改变可能是一场噩梦,如果这意味着其他报告出错了,那么你必须改变它的工作方式的逻辑,然后重新测试系统中的每个报告布局......