我有两个数据模型,由以下类表示:
1) ImagesSet - 拥有 2DImage 的对象,每个 2DImage 都有自己的位置(原点( 3DPoint ),x轴,y轴( 3DVector )和沿x和y轴的尺寸(以像素为单位)),但像素尺寸相同(以mm为单位),角度在x和y轴之间(90度)
此对象具有以下方法(伪代码):
2) 3DImage - 与第一个类似但具有以下限制的对象: 它只能存储沿x轴和y轴具有相同x轴,y轴和尺寸的2D图像。
在这种情况下从 ImagesSet 派生 3DImage 是否正确? 从我的观点来看, 3DImage "是一个" ImagesSet (但限制较少) 我可以在这里申请利斯科夫替代原则吗?
在这种情况下,如果我们尝试使用另一个x,y轴添加图像 - 方法 AddImage 将引发异常或返回错误。
提前致谢, 塞吉
答案 0 :(得分:4)
可能只是我,但每当我听到"派生或不派生"我的第一反应"没有衍生出来" :)
在这种情况下有两个原因:
LSP完全违反了这些"小限制"。因此,在基类中AddImage
允许添加任意方向的图像之前,3DImage
不 ImagesSet
。算法无法表明他们需要此功能(并且评论不是一个好地方:)),因此您必须依赖运行时检查。它仍然可以用这种方式编程,但这对于开发人员来说将是一个额外的开销。
每当你创建一些抽象时,理解为什么要创建它是很重要的。通过派生,您可以隐式地创建一个抽象 - 它是3DImage
的接口。而不是这样,明确地创建这个抽象更好。创建一个接口类,列出那些对能够处理这两种数据结构的算法有用的方法,并使实现该接口的ImagesSet
和3DImage
可能添加一些其他方法。
P.S。
可能AddImage
将成为这些添加方法之一 - ImagesSet
和3DImage
不同,但这取决于......
答案 1 :(得分:4)
我同意maxim1000将违反LSP,因为派生类添加了基类中不存在的限制。如果你仔细看看你的描述,你会发现问题可以颠倒过来:ImageSet可以从3DImage派生吗?
您的情况与Ellipse-Circle问题有些类似。哪一个来自另一个?圆是带有约束的椭圆,还是椭圆是带有额外半径的圆?关键是两者都是错的。如果将椭圆约束为相等的半径,则尝试设置不同值的客户端将收到错误。
否则,如果我们说椭圆只是一个不太受约束的圆圈,我们会得到一个更微妙的错误。假设形状可能不会破坏屏幕的边界。现在假设用椭圆代替圆。根据测试的坐标,形状可能会突破屏幕区域而不更改客户端代码。这确实违反了LSP。
结论是 - 圆和椭圆是分开的类; 3DImage和ImageSet是单独的类。
答案 2 :(得分:0)
亲爱的maxim1000和sysexpand,
感谢您的回答。我同意你的看法。现在很明显违反了LSP,在这种情况下,我无法从 ImagesSet 派生 3DImage 。
我需要按以下方式重新设计解决方案:
2DImage 将包含:
2DImageOrientated 将派生自 2DImage ,并将包含新数据:
我将创建纯接口 IImagesSet :
ImagesSet 将来自 IImagesSet ,并将包含以下内容:
3DImage 也将来自 IImagesSet ,并将包含以下内容。
在这种情况下,我认为LSP没有被违反。