如此重要的原理“OCP”是如何实现的?这会是大量代码重复实践的原因吗?

发布于 2024-08-05 02:20:20 字数 655 浏览 4 评论 0原文

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还有其他解释吗?

OCP (Open/Closed Principle) is one of the SOLID principles. Which is says:

”Software Entities should be Open for Extension, but Closed for Modification.”

It take me while to understand the above sentence about OCP. And when I start read more about it, I found it make sense and so useful, but in the mean time I noticed it cause duplicated code.

How such an important principle "OCP" will be the reason of massive code duplication practice?

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 ....");
        }   
    }
 }

Am I missing something here? Is there another way for OCP to be explained?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

嗼ふ静 2024-08-12 02:20:20

代码重复是指块、语句甚至公共成员声明分组的大量重复。它不是指语言关键字、标识符、模式等的重复。否则您将无法实现多态性。

您提供的示例并未真正演示开放/封闭原则,因为您尚未演示如何在不进行修改的情况下扩展给定类的行为。开放/封闭原则是指每次需要不同行为时创建新类。这可以使用继承和模板方法模式来实现(即调用基类中的抽象或虚拟方法,这些方法在子类中被重写以实现所需/新的行为),但更常见的是使用策略模式的组合来演示(即将变体行为封装在类中并将其传递给封闭类型以用于确定所实现的整体行为)。

从您的示例来看,您似乎更多地考虑尝试通过继承来实现 OCP,但从基本报告格式化程序开始,建立带有子类型的接口来指示给定报告的不同类型的格式实际上是一个良好的开始通过构图显示 OCP。使用基于组合的方法演示 OCP 需要一个使用格式化程序的类……比如 ReportWriter。

public class ReportWriter : IReportWriter
{
    Write(IReportData data, IReportFormatter reportFormatter)
    {
         // ...

         var formattedStream = reportFormatter.Format(data, stream);

        // ...
    }
}

只是为了演示,我对新格式化程序的行为方式做了一些假设,因此不要过分关注该部分。需要关注的是,ReportWriter 通过允许传入新的格式化程序来进行扩展,从而影响报告的最终编写方式,但对于实现这种新行为所需的代码修改(即 if 语句、switch 的存在)是关闭的。报表等多种方式实现格式化)。

开放/封闭原则不仅不会导致代码重复,当通过使用组合而不是继承来实现时,它实际上可以帮助减少重复。如果在创建继承层次结构或策略类的过程中发生真正的代码重复,那么这表明存在与您尝试实现 OCP 的上下文中可能存在的分解问题无关的问题。

Code duplication refers to the significant repeating of blocks, statements, or even groupings of common member declarations. It doesn't refer to the repeating of language keywords, identifiers, patterns, etc. You wouldn't be able to achieve polymorphism otherwise.

The example you provide doesn't really demonstrate the Open/Closed Principle because you haven't demonstrated how a given class's behavior can be extended without modification. The Open/Closed principle is about creating new classes each time variant behavior is desired. This can be achieved using inheritance along with the Template Method pattern (i.e. calling abstract or virtual methods in a base class which are overridden in subclasses to achieve the desired/new behavior), but it's more often demonstrated using composition using the Strategy pattern (i.e. encapsulating the variant behavior in class and passing it to the closed type to be used in determining the overall behavior achieved).

From your example, it appears you were thinking more along the lines of trying to achieving OCP through inheritance, but starting with a base report formatter to establish the interface with subtypes to indicate different types of formats for a given report is actually a good start toward showing OCP through composition. What's needed to demonstrate OCP with a composition-based approach is a class which consumes the formatters ... say a ReportWriter.

public class ReportWriter : IReportWriter
{
    Write(IReportData data, IReportFormatter reportFormatter)
    {
         // ...

         var formattedStream = reportFormatter.Format(data, stream);

        // ...
    }
}

Just for the sake of demonstration, I've made some assumptions about how our new formatter might behave, so don't focus too heavily on that part. The thing to focus on is that ReportWriter is open for extension by allowing new formatters to be passed in, thus affecting how reports are ultimately written, but closed for modification of code needed to achieve this new behavior (i.e. the presence of if statements, switch statements, etc. to achieve multiple ways to format).

Not only does the Open/Closed principle not cause code duplication, when achieved through the use of composition over inheritance it actually can help reduce duplication. If true code duplication occurs in the course of creating your inheritance hierarchy or strategy classes then that points to a factoring issue unrelated to the fact that it might exist in the context of you trying to achieve OCP.

泪之魂 2024-08-12 02:20:20

你所拥有的对我来说看起来非常好。您没有修改 ReportFormatter,而是扩展了它。

What you have looks perfectly fine to me. You didn't modify ReportFormatter, you extended it.

财迷小姐 2024-08-12 02:20:20

类似的问题可以通过更好的方法设计来解决。请考虑以下几点:

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");
        }       
    }
 }

我认为按照这些思路进行设计将是消除重复代码的最佳方法。

Something like this could be solved with better design of the methods. Consider the following instead:

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");
        }       
    }
 }

I think design along these lines would be your best shot of eliminating duplicated code.

清眉祭 2024-08-12 02:20:20

我自己实现了自定义格式报告系统,我想说这种方法已经是错误的。

当您将格式作为构造函数的参数提供时,为什么要为每种格式提供一个格式化程序类?格式化程序类构造函数(甚至是 ReportFormatter 类的静态格式化方法)应该有一个报告和一个格式描述作为参数,并相应地格式化报告。

不需要为每种格式创建一个类。

Having implemented a custom format report system myself, I'd say the approach is wrong already.

Why have a formatter class for each format when you give the format as an argument to the constructor? The formatter class ctor (or even the static format method of the ReportFormatter class) should have a report and a format description as arguments and format the report accordingly.

There is just no need for a class for each format.

稀香 2024-08-12 02:20:20

像这样的东西应该有效。

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 的客户端不需要更改(假设其他地方有一些处理设置的机制)。
  • 可以添加对通用格式化功能的改进来改进所有报告,因此没有重复的代码,
  • 您只需要在某些特定情况下更好地工作,您可以进行更改

这是关键的第三点:您可以说“在原则上,如果注释使行太大而无法容纳,智能布局例程应该知道从日期中删除年份。但在实践中实施这一更改可能是一场噩梦,如果这意味着其他报告会出现错误,因此您必须更改其工作原理,然后重新测试系统中的每个报告布局......

Something like this should work.

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");
        }       
    }
 }

That means:

  • clients of ReportFormatter don't need to change (assuming some mechanism elsewhere that handles setup).
  • an improvement to generic formatting capabilities can be added to improves all reports, so no duplicated code
  • you just need things to work better in some particular case, you can just make that change

It's the third point that is the key: you can say 'in principle, the smart layout routine should know to drop the year from the date if the comment makes the row too big to fit'. But implementing that change in practise can be a nightmare, if it means that then the other report comes out wrong, so you have to change the logic of how it all works then retest every report layout in the system...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文