问题

如果我现在想定义Windows这个类,之后让它继承Rectangle这个类,这样做对么?

回答
设想一下,我们要描绘现实世界中的事物。比如,我们有一个“形状”的概念,它有很多共同的特征,比如我们能知道它在哪里,有多大。然后,我们有了更具体的“矩形”的概念,它也是形状的一种,但它有四个直角,边是成对相等的。

现在,我们要定义一个“Windows”类。你想让它继承“Rectangle”类。这背后的想法是,你觉得“Windows”这个东西,在很多方面和“矩形”很像。

为什么这个想法听起来不错?

首先,一个窗口在屏幕上,它占据了一个区域,这个区域在通常情况下,我们可以想象成一个矩形。就像你在纸上画一个窗口,你很可能会画一个矩形框。所以,“Windows”继承“Rectangle”意味着,“Windows”类自动拥有了“Rectangle”类所定义的所有属性和行为。

打个比方,“Rectangle”可以定义一些基本的东西,比如:

位置: 窗口在屏幕上的左上角坐标 (x, y)。
尺寸: 窗口的宽度 (width) 和高度 (height)。
绘制能力: 可能有一个方法,用来画出这个矩形。

如果“Windows”继承了“Rectangle”,那么“Windows”对象就自然而然地拥有了这些“位置”和“尺寸”的属性,也可能拥有了“绘制”这个能力。这省去了我们为“Windows”重新定义这些基础属性的工作,就像我们不用每次都教一个新人怎么站立和行走一样,因为这是“人”这个概念里就包含的。

但是,这里面也存在一些需要仔细考虑的地方。

“继承”不仅仅是“看起来像”这么简单,它还意味着一种“isa”的关系。也就是说,“Windows” 是 “Rectangle”的一种。

“isa”关系是否真的成立?
一个窗口,在很多时候确实可以被看作一个矩形区域。但是,一个真正的“Windows”类,通常还会有很多“Rectangle”所不具备的特质,比如:
标题栏 (Title Bar): 窗口顶部通常有一个区域,显示标题,并且可以拖动窗口。
边框 (Border): 窗口可能有不同样式的边框,影响其视觉表现。
最小化、最大化、关闭按钮 (Minimize, Maximize, Close buttons): 这些是窗口交互的重要组成部分。
内容区域 (Content Area): 窗口里面真正显示用户数据的部分。
状态: 窗口可能是激活的、最小化的、隐藏的等等。
事件处理: 窗口需要响应鼠标点击、键盘输入等事件。

这些特性,“Rectangle”类本身并没有定义。如果“Windows”直接继承“Rectangle”,那么“Windows”对象就拥有了“Rectangle”的所有东西,但“Rectangle”的一些概念,比如“只有一个简单的矩形区域”,可能就与“Windows”的实际复杂性产生了冲突。

“isa”的反面:
反过来想,一个“Rectangle”对象,它一定是一个“Windows”吗?显然不是。一个独立的矩形,它可能只是一个图形元素,比如背景的填充色块,或者是一个简单的几何图形,它不需要有标题栏、按钮或者响应事件。

另一种更常见的做法:组合 (Composition)

在很多面向对象的设计中,我们更倾向于使用“组合”而不是“继承”,来处理这种“hasa”的关系。

“组合”的意思是,“Windows”类 拥有 一个“Rectangle”对象,而不是“是”一个“Rectangle”对象。

举个例子:

Windows 类里面可以有一个名为 `boundary` (边界) 的私有成员变量,它的类型是 Rectangle。
在 Windows 类的构造函数里,我们可以创建一个 Rectangle 对象,并将其赋值给 `boundary`。
当我们需要知道窗口的位置和尺寸时,我们不是直接访问 Windows 对象的 `x` 或 `width` 属性(因为这些属性可能不在 Windows 类里),而是通过 `window.boundary.getX()` 或者 `window.boundary.getWidth()` 来获取。
Windows 类可以定义自己的方法,比如 `drawTitleBar()`, `handleCloseClick()`,这些是 Rectangle 类所不具备的。

为什么组合在这里可能更合适?

1. 更强的灵活性: 如果你将来需要一个CircleWindow(圆形窗口)或者RoundedRectangleWindow(圆角矩形窗口),如果“Windows”直接继承“Rectangle”,这个设计就会变得很麻烦,因为圆形和圆角矩形都不是严格意义上的“Rectangle”。但如果使用组合,你只需要改变 `boundary` 变量的类型,让它指向一个 Circle 或者 RoundedRectangle 对象即可,而 Windows 类本身的核心逻辑(处理标题栏、按钮等)可以保持不变。
2. 更清晰的职责划分: “Rectangle”类可以专注于描述一个矩形区域的几何属性和基本操作。而“Windows”类则可以专注于窗口的生命周期管理、用户交互、内容呈现等更高级的特性。它们各自的职责更加明确。
3. 避免“脆弱基类”问题: 如果“Rectangle”类在未来发生改变,比如修改了绘制某个方法的内部逻辑,那么所有继承它的子类(包括“Windows”)都可能会受到影响,甚至出现意想不到的问题。组合则可以将这种影响限制在“Rectangle”类本身,或者只影响那些直接使用“Rectangle”部分的代码。

总结来说:

你提出的让“Windows”继承“Rectangle”的想法,在概念上是可行的,并且能让“Windows”类快速获得矩形的基本属性。但从更深层次的软件设计原则和未来的可维护性、灵活性来看,组合(让“Windows”类包含一个“Rectangle”对象)通常是更被推荐和更健壮的设计方式。这就像说,一个“汽车”有一个“轮子”对象,而不是一个“汽车”是一个“轮子”一样,它们之间的关系更倾向于“拥有”而非“属于”。

网友意见

user avatar

我同意

@vczh

的观点,但我倒不认为这是is a的流毒。

事实上是很多人根本就搞不清什么是is a xxx。

X is a Y的一个我认为相对正确理解是,所有的X是所有的Y的真子集。

然后我们来套一下就知道了

所有的窗口是所有的矩形的真子集。

好像有点不对,窗口和矩形有神马关系。

我相信你不会指着你家的窗子说,这是个矩形,然后指着你家的挂钟说,这是个圆形,,,,


再想一下我们是怎么把窗口和矩形结合起来的?

事实上一个读起来比较正常的句子是:窗口是矩形

千万别丢了这个,有没有这个含义可完全不一样。


我们不会说,苹果是水果的。

所以,窗口是矩形的,这个描述真实的含义是:窗口是个矩形的容器,窗口是个矩形的控件,窗口是个矩形的XX。


如此一来,窗口是不是个矩形简直就是呼之欲出的事情。



至于窗口到底是个啥,事实上我非常不建议任何初学者从神马窗口这种东西开始构建自己的设计。在XX是YY这种概念都不能清晰的分辨的时候,从窗口这种高度具象和复杂的东西出发,弄出来的东西必然是惨不忍睹的。



OOD做多了,像C#这样的单根继承体系怎么设计基本已经是本能了,我也随便贡献一个吧,以Windows操作系统里面的窗口为例,初步的构想是这样的:

       //标准的应用程序窗口 public class ApplicationWindow : StandardWindow, IMenuContainer, IToolbarContainer  //标准窗口,指矩形窗口 public class StandardWindow : WindowBase, IDialog, IResizable  //窗口基类 public class WindowBase : LayoutControl  //布局控件 public class LayoutControl : ContainerControl  //容器控件 public class ContainerControl : Control  //控件 public class Control : IVisual  //对话框,指有标题和关闭按钮的矩形可视化容器。 public interface IDialog : IRectangleVisual, IClosable, ITitleContainer  //可以调整大小的矩形容器 public interface IResizable : IRectangleVisual  //呈现为矩形区域的视觉控件 public interface IRectangleVisual : IVisual  //需要绘制的东西 public interface IVisual  //具有目录条的容器 public interface IMenuContainer  //具有工具条的容器 public interface IToolbarContainer  //可以关闭的视觉控件 public interface IClosable : IVisual      

可以看出来,在我的设计里,矩形这一特征,还是被保留在继承体系中,但是只是其中一个很小的小枝。

类似的话题

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有