问题
I have two data models which are represented by the following classes:
1) ImagesSet - an object that owns 2DImage's, each 2DImage has its own position (origin(3DPoint), x-,y-axes(3DVector) and dimension along x and y axes(in pixels)), but the same pixel size(in mm for example), angle between x and y axes(90 degrees)
This object has following methods(in pseudo code):
- AddImage(2DImage);
- RemoveImage(ImageIndex);
- number GetNumberOfImages();
- 2DImage Get2DImage(ImageIndex);
2) 3DImage - an objects that is similar to the first but with following restrictions: it can store 2D images only with the same x-,y-axes and dimensions along x and y axes.
Is it correct in this case to derive 3DImage from ImagesSet? From my point of view 3DImage "is a" ImagesSet (but with small restrictions) Could I apply here Liskov substitution principle?
In this case if we are trying to add an image with another x,y axes - method AddImage either will throw an exception or return an error.
Thanks in advance, Sergey
回答1:
I agree with maxim1000 that LSP will be violated because derived class adds restrictions that are not present in the base class. If you take a close look at your description you will notice that the question can be turned upside-down: Can ImageSet derive from 3DImage?
Your situation is somewhat similar to Ellipse-Circle problem. Which one derives from the other? Is circle an ellipse with a constraint, or is an ellipse a circle with additional radius? The point is that both are wrong. If you constrain ellipse to equal radiuses, then client which attempts to set different values would receive an error.
Otherwise, if we say that ellipse is just a less constrained circle, we get a more subtle mistake. Suppose that shapes may not breach boundaries of the screen. Now suppose that a circle is replaced with an ellipse. Depending on which coordinate was tested, the shape might break out of the screen area without changing the client code. That is the exact violation of LSP.
Conclusion is - circle and ellipse are separate classes; 3DImage and ImageSet are separate classes.
回答2:
May be it's just me, but whenever I hear "derive or not derive" my first reaction "not derive" :)
Two reasons in this case:
LSP is violated exactly because of those "small restrictions". So until you have
AddImage
in your base class which allows to add an image with any orientation,3DImage
is not anImagesSet
. There will be no way for algorithms to state that they need this feature (and comments is not a good place :) ), so you'll have to rely on run-time checks. It's still possible to program in this way, but this will be one more overhead for developers.Whenever you create some abstraction, it's important to understand why exactly it's created. With derivation you implicitly create an abstraction - it's interface of
3DImage
. And instead of this it's better to create this abstraction explicitly. Create an interface class, list there methods useful for algorithms able to work on both data structures and make bothImagesSet
and3DImage
implementing that interface possibly adding some other methods.
P.S.
And likely AddImage
will become one of those added methods - different in ImagesSet
and 3DImage
, but that depends...
回答3:
Dear maxim1000 and sysexpand,
Thanks for the answers. I agree with you. It is clear now that LSP is violated and in this case I can't derive 3DImage from ImagesSet.
I need to redesign the solution in the following way:
2DImage will contain:
- 2DDimension's
- PixelSize(in mm)
- PixelData
2DImageOrientated will be derived from 2DImage and will contain new data:
- 3DPoint origin,
- 3DVector x-,y-axes
I will create pure interface IImagesSet:
- number GetNumberOfImages()
- RemoveImage(ImageIndex)
- 2DImageOrientated Get2DImage()
ImagesSet will be derived from IImagesSet and will contain the following:
- vector<2DImageOrientated>
- Add2DImage(2DImageOrientated)
- number GetNumberOfImages()
- RemoveImage(ImageIndex)
- 2DImageOrientated Get2DImage()
3DImage will be also derived from IImagesSet and will contain the following.
- vector<2DImageOrientated>
- Add2DImage(2DImage)
- SetOrigin(3DPoint)
- SetXAxis(3DVector)
- SetYAxis(3DVector)
- number GetNumberOfImages()
- RemoveImage(ImageIndex)
- 2DImageOrientated Get2DImage()
In this case I think LSP is not violated.
来源:https://stackoverflow.com/questions/25973235/can-i-apply-here-liskov-substitution-principle