适合初学者的松耦合和面向对象实践

发布于 2024-07-15 08:38:41 字数 524 浏览 7 评论 0原文

保持类松散耦合是编写易于理解、修改和调试的代码的一个重要方面——我明白了。 然而,作为一个新手,几乎任何时候我都很难超越最简单的例子。

我或多或少地了解如何将字符串、整数和简单数据类型封装在它们自己的类中。 然而,当我开始处理富文本格式等信息时,事情变得非常复杂——除非我只使用组件中已有的各种方法。 为了继续这个示例,假设我正在编写一些在 UI 中包含 RTF 备忘录组件的内容。 在 Delphi 中,该组件具有用于执行诸如保存格式化文本之类的操作的内置方法。 此外,有时似乎处理 RTF 文本本身的唯一(或至少是最佳)方法是通过再次内置于组件中的方法。

当我已经有一个可以为我完成所有这些工作的组件时,如何(或为什么)在另一个类中完成所有保存、加载和格式化文本的工作?

就我自己而言,我通常最终要么(a)做一些看起来比需要复杂得多的事情,重新发明已经存在的方法,要么(b)创建仍然彼此紧密耦合的做得很差的类。 正如他们在电视广告中所说,“必须有更好的方法!”

我只是在概念上迷失了“更好的方式”如何运作。 有什么想法吗?

Keeping classes loosely coupled is an important aspect of writing code that is easy to understand, modify, and debug--I get that. As a newbie, though, just about anytime I get beyond the most simple examples I struggle.

I understand, more or less, how I can encapsulate strings, integers, and simple data types in classes of their own. When I start dealing with information like rich text formatting, however, things get really complicated--unless I just use the various methods already present in a component. To continue this example, suppose I was writing something that included an RTF memo component in the UI. In Delphi, the component has built-in methods for doing things like saving formatted text. In addition, sometimes it seems like the only (or at least best) ways to work with the RTF text itself is via methods again built into the component.

How (or why) would I do all the work of saving, loading, and formatting text in another class when I already have a component that does all of this for me?

On my own I usually end up either (a) doing something that seems much more complicated than need be, reinventing methods already present, or (b) creating poorly done classes that are still tightly coupled to one another. As they say in informercials, "There has to be a better way!"

I'm just lost conceptually on how that 'better way' works. Any thoughts?

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

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

发布评论

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

评论(4

半衬遮猫 2024-07-22 08:38:41

我相信您错过了一些基本概念。

OOP 背后的理念始于离散的、可重用的逻辑单元。 重点是创建自给自足的模块。

对于 RTF 备忘录组件,它通过处理给定的数据集(备忘录)来满足上述标准,使得您的程序和程序中的其他对象不关心它如何工作。 它的目的是显示界面、接受数据、操作特定数据并将该数据传递到程序的另一部分。

松散耦合背后的想法很简单,您可以用另一个满足以下条件的控件替换该备忘录控件:接口规格相同。 也就是说,您可以实例化它,让用户与其交互,并在必要时提取数据。

松散耦合与关注点分离(SoC); 这是将程序分解为不同功能的过程,以减少功能重叠并使其更易于管理。 但它们不是同一件事。 顺便说一句,这也是从过程式编程风格转向 OOP 的主要驱动力之一。 由于 OOP 迫使编程根据相关和离散的功能进行思考。

听起来你真的在问SoC。

实现SoC的方法有很多种。 有时,它涉及将 UI、处理逻辑和持久层分开(例如考虑 MVC 设计模式)。 有时只是将相关功能放在一起以降低复杂性; RTF 控件已经通过包含操作数据所需的所有函数来实现这一点,这样您就不再有进一步的依赖性。

I believe you've missed on some basic concepts.

The idea behind OOP starts with discrete, reusable units of logic. With an emphasis on creating self-sufficient modules.

In the case of the RTF Memo component, it meets the above criteria by handling a given set of data (the memo) in such a way that your program and other objects within your program don't care how it does it's job. It's purpose is to show an interface, accept data, manipulate that specific data, and pass that data on to another part of your program.

The idea behind being loosely coupled is simply that you can replace that memo control with another control which meets the same interface specifications. Namely, that you can instantiate it, let the user interact with it, and pull the data out when necessary.

Being loosely coupled goes hand in hand with the idea of Separation of Concerns (SoC); which is the process of breaking a program into distinct features in order to reduce overlapping functionality and make easier to manage. But they are not the same thing. Incidentaly, this was also one of the main drivers behind moving away from the procedural style of programming into OOP. As OOP forces the programming to think in terms of related and discrete functionality.

It sounds like you are really asking about SoC.

There are many ways to achieve SoC. Sometimes it involves keeping the UI, processing logic, and persistance layers separated (consider the MVC design pattern for example). Sometimes it is simply keeping related functions together in order to reduce complexity; which the RTF control already does by containing all of the functions necessary to manipulate the data so that you don't have further dependencies.

自由如风 2024-07-22 08:38:41

我建议使用两个概念:接口和依赖注入,作为解耦类的一种方法。 接口为您提供了一种定义独立于任何实现的契约或一组预期行为的方法。 当您的类依赖于接口而不是类时,您可以自由地替换实现该接口的其他类,而无需重写依赖于该接口的类。

当您使用带有依赖注入的接口时,即为类提供它要处理的实际实现,而不是让它自己创建特定的实现,您可以在应用程序中实现更多的解耦。 现在类只知道接口,甚至不知道如何创建它,只是使用它。 依赖注入通常与创建模式(例如 Builder 或 Factory)一起使用,在这些模式中,您可以在单个类中本地化对象的构造,以便在使用其他类扩展应用程序时仅需要更改该类。

另外,请记住,耦合(及其双胞胎,内聚力)是一个相对度量。 您无法消除所有耦合,否则您的对象将无法交互。 一定程度的依赖是必要的。 您还需要在易用性和实施​​之间取得平衡。

至于你的具体例子,没有实际的代码很难判断。 我怀疑您过度设计了解决方案并违反了 DRY 原则(不要重复自己)。 您可能需要研究使用接口的方法,或许还有一个轻量级包装器来将您的类与框架组件解耦,而不是完全重新实现。

I would suggest two concepts, interfaces and dependency injection, as a way to decouple your classes. Interfaces give you a way to define a contract or set of expected behaviors that is independent of any implementation. When you have a class depend on an interface rather than on a class, you get the freedom to substitute other classes that implement the interface without having to rewrite the class that is depending on it.

When you use interfaces with dependency injection, i.e., give the class the actual implementation that it is to work on rather than have it create a particular implementation on its own, you achieve even more decoupling in your application. Now the class only knows about the interface and doesn't even know how to create it, just use it. Dependency injection is often used with creational patterns such as Builder or Factory, where you localize the construction of objects in a single class so that only that class need change when you extend the application with additional classes.

Also, remember that coupling (and its twin, cohesion) is a relative measure. You can't eliminate all coupling or your objects wouldn't be able to interact. Having some level of dependence is necessary. You need to balance it with ease of use and implementation as well.

As for your particular example, it's hard to tell without actual code. I suspect that you are over-engineering the solution and violating the DRY principle (don't repeat yourself). You may need to look at ways to use interfaces and perhaps a lightweight wrapper to decouple your classes from the framework component rather than a complete reimplementation.

神经大条 2024-07-22 08:38:41

好吧,我对这个问题并不完全清楚,但策略模式似乎在这里可行。

基于父 RTF 对象构建一个对象,但将存储等处理方法设置为具有自己方法的定义对象。

这可以实现组合的强大功能,而无需严格继承所有父方法,并且您不必构建巨大的自定义对象,只需替换您需要的方法即可。

Well, I'm not completely clear on the question, but it almost seems like the strategy pattern would work here.

Build an object based on your parent RTF object but set the handling methods for storing, etc. as defined objects with their own methods.

This enables the power of composition without strictly inheriting all the parent methods and you don't have to build a huge custom object, just replace the methods you need to.

挽袖吟 2024-07-22 08:38:41

您选择的示例相当复杂。

当你说 rtf memo 组件是非常松散耦合时,你是对的。 如此松散,以至于它实际上不可扩展,只能按原样使用,因为它
集成了表示/视图、控制器和模型。

如果您想查看设计良好、可扩展的富文本系统的示例,请查看 OS X 文本系统(或 Gnustep,如果您想阅读代码)。 它很复杂,因为需要做出很多设计决策,并且需要从一个模块隐藏到另一个模块。 在那里您可以直接在良好的结构中工作。

rtf memo 组件的使用范围有限,您可能必须使用设计良好的类来解决这个问题:

  • 只有当您不需要在程序中保存其他数据时,组件数据的加载和保存才有意义。相同的文件/数据库。
  • 它也不能很好地处理大量数据。
  • 它只能理解 rtf 的一小部分。

The example you picked is rather complex.

You are right when you say that the rtf memo component is very loosely coupled. So loosely, that it is practically not extendable, and can only be used as is, as it
integrates presentation/view, controller and model.

If you want to see an example of a well designed, extensible rich text system, take a look at the documentation of the OS X text system (or Gnustep, if you want to read the code). It is complex, because there are a lot of design decisions that need to be made and need to be hidden from one module to the other. There you can directly work in a good structure.

The rtf memo component has a limited scope of use, which you might have to work around using well-designed classes:

  • The loading and saving of the components data only make sense if you don't have to save other data in your program in the same file/db.
  • It also doesn't handle large amounts of data well.
  • And it only understands a small subset of rtf.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文