I'm very new to the SOLID design principles. One thing I had problem with understanding is the "Square-rectangle" example of a Liskov Substition Principle violation. Why should the Height/Width setter of a Square override the ones of a Rectangle? Isn't this exactly what's causing the problem when there's Polymorphism?
Doesn't removing this solve the problem?
class Rectangle
{
public /*virtual*/ double Height { get; set; }
public /*virtual*/ double Width { get; set; }
public double Area() { return Height * Width; }
}
class Square : Rectangle
{
double _width;
double _height;
public /*override*/ double Height
{
get
{
return _height;
}
set
{
_height = _width = value;
}
}
public /*override*/ double Width
{
get
{
return _width;
}
set
{
_width = _height = value;
}
}
}
class Program
{
static void Main(string[] args)
{
Rectangle r = new Square();
r.Height = 5;
r.Width = 6;
Console.WriteLine(r.Area());
Console.ReadLine();
}
}
Output is 30 as expected.
Imagine the user is implementing a bounding box in a GUI application, similar to this:
They want to represent this blue box by a Rectangle class, so that if the user clicks & drags down its height will increase; if the user drags right, its width will increase.
LSP states that a client should be able to use a derived class (Square) wherever you would use its superclass (Rectangle) without breaking the business logic of Rectangle — i.e. a user should be able to sub in one for the other & the rest of their code shouldn't break.
But the following are incompatible with each other:
It's an assumed post-condition of Rectangle that it's setter methods won't cause side effects (i.e. setWidth shouldn't affect the height)
It's inherent to the logic of a Square that its width will always equal its height.
If the programmer used Square instead of Rectangle, their assumption above wouldn't work, as if the user dragged down, the box would get bigger horizontally & vertically at the same time.
The trouble with the Square/Rectangle example is that we're assuming too much about Rectangle to begin with. A rectangle can have a different length to its height, but this is a property of a specific type of rectangle (an oblong rectangle).
A square is a rectangle, but a square is not an oblong rectangle. If we want to assume the behaviour of an oblong about our Rectangle class (that it's width & height can differ), it's then doesn't make sense for our Square class to extend from that.
The LSP states that substituting an object of a subclass should not change the behaviour, or the correctness, of the program. The classes you specify do change the correctness. With a rectangle, the client of the class expects that the height and width are independently settable. When you subclass with Square, this is no longer the case.
A client setting a width of 5 and a height of 10, whilst reference an object that happens to be a Square but is held in a Rectangle variable, will get different results according to the order in which they set the height and width properties. They might get a 5x5 rectangle or a 10x10 one. Either case will be unexpected.
There's Barbara's original complex description of LSP but Uncle Bob's makes it easier - "Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it". This is broken with the Square/Rectangle problem.
I wrote an article about this at http://www.blackwasp.co.uk/SquareRectangle.aspx.
Related
I have read from other sources that it isn't a good idea for objects to know about each other especially the ones on same level. It should be more like hierarchy.
My problem is quite unique as I haven't figured out a way around it. Also I have been unlucky to come across any topic that addresses my issue specifically.
The problem
I am building a chess app and I am constructing the model of the app. Right now I have an abstract objects like for example Piece which other pieces like Queen, Knight and the rest would inherit from.
I also have a Board class which handles all board model and state of a game. Now each of my piece has a generateMove() method to calculate possible moves from their position and to do this they need to know the state of the board. Also the Pieces are been instantiated by Board at startup.
Question
Do I go ahead and instantiate Pieces by e.g
public class ChessBoard{
Boardbit = 64bit
Knight = new Knight(start_position, this)
//calculate
}
and then in Knight class method
public long generateMove(ChessBoard);
If no, what other ways can I go about it?
Making Chessboard to know the Knight and vise versa is not elegant. I agree with you in this point. Kind of sticking with the 'Tell don't ask' rule forces the 'higher level' element, in this case the chessboard, to tell the piece to move while providing all the required information. The Chessboard itself doesn't know which piece is moving (in this case of predicting possible moves for all pieces), but for sure never knows any details about how a piece can move or is allowed to move. This is just one possible solution using sort of Strategy Pattern. (The Visitor or some similar pattern could also be used here):
Main() {
chessboard = new Chessboard()
PiecesCollection = new PiecesCollection(new Knight(KnightStrategy, Color.Black))
chessboard.AddPieces(PiecesCollection)
CollectionOfAllPossibleMoveCollections = chessBoard.CallculateAllPossibleMoves()
Move selectedMove = ShowOrSelectMove(CollectionOfAllPossibleMoveCollections)
chessboard.ExecuteMove(selectedMove)
}
public class Chessboard{
// fields
PiecesCollectionWhite
// where 'PiecesCollectionWhite' is a collection of `Piece`
PiecesCollectionBlack
// where 'PiecesCollectionBlack' is a collection of `Piece`
CurrentlyVisitedPositionsCollection
// where 'CurrentlyVisitedPositionsCollection' is a collection of `Position`
// methods
AddPieces(PiecesCollection, Color)
CallculateAllPossibleMoves(Color) {
CollectionOfPossibleMoveCollections =
FOREACH Piece IN PiecesCollection OF Color
DO Piece.CalculateMoves(this.CurrentlyVisitedPositionsCollection)
return CollectionOfAllPossibleMoveCollections // where 'CollectionOfAllPossibleMoveCollections ' is a collection that holds a collection of `Move` of which each nested collection represents the possible moves of a chess piece.
}
ExecuteMove(Move) {
RemovePieceFromBoardIfNecessary(Move.ToPosition)
}
}
public class Piece
{
// fields
Strategy
Position
Color
// methods
CallculateMoves(CurrentlyVisitedPositionsCollection) {
PossibleMovesCollection = this.Strategy.Execute(CurrentlyVisitedPositionsCollection, this.Position)
return PossibleMovesCollection where `PossibleMovesCollection` is a collection of `Move`
}
}
public class Knight extends Piece
{
ctor(Strategy, Color)
}
public class Stragtegy
{
abstract Execute(currentPosition, allPiecesPositions) : PossibleMovesCollection
}
public class KnightStrategy extends Strategy
{
Execute(currentPosition, allPiecesPositions) {
PossibleMovesCollection = ApplyKnightMoveAlgorithm()
return PossibleMovesCollection
}
private ApplyKnightMoveAlgorithm() : PossibleMovesCollection
}
public class Move
{
Position fromPosition
Position toPosition
}
public class Color
{
Black
White
}
public class Position
{
Color
xCoordinate
yCoordinate
}
This is just a sketch and not a complete example. There is some state information or operations missing. E.g. maybe you would have to store the Color that was moved last on the chessboard.
Since the Chessboard returns all possible moves (information about all currently visited coordinates) you can easily enhance the algorithm by implementing some intelligence to predict the best possible moves from this information. So before the controller or in this case the Main() will call Chessboard.ExecuteMove(Move) it could make a call to PredictionEngine.PredictBestMove(CollectionOfAllPossibleMoveCollections).
Much better is to have method generateMove(boardState), so your Board should call whatever piece you have and pass them the necessary information for such task. It can be used even for some optimization as board can pregenerate some good-to-use structure each round only once and then pass it to all the pieces (like some 2d array).
In the book "Agile Software Development: Principles, Patterns, and Practices", the "Single Responsibility Principle" section has an example about a class Rectangle which has more than one responsibility:
class Rectangle {
public void draw() { ... }
public double area() { ... }
}
And different classes may use only one of its methods:
class ComputationalGeometryApplication {
Rectangle rectangle;
public void someMethod() {
double area = rectangle.area();
}
}
class GraphicalApplication {
Rectangle rectangle;
public void someMethod() {
rectangle.draw();
}
}
(Note: The book takes c++ for example, and I use Java code here since I'm not familiar with c++)
I'm not clear about this sentence:
Second, if a change to the GraphicalApplication causes the Rectangle to change for some reason, that change may force us to rebuild, retest, and redeploy the ComputationalGeometryApplication.
Say if GraphicalApplication causes the draw() method to become draw(boolean), why will it force us to rebuild, retest, and redeploy the ComputationalGeometryApplication?
I mean,
ComputationalGeometryApplication can choose to use the old version of compiled file of Rectangle if we know the changes causes by GraphicalApplication is not related with itself
If ComputationalGeometryApplication wants to use the new version of Rectangle, yes, we should rebuild/retest/redeploy. But even if the draw() method is not in Rectangle, but in another class of same codebase, we still need to rebuild/retest/redeploy the ComputationalGeometryApplication if we want to use the new version of the library which contains Rectangle
I can't really understand the benefit, what am I missing?
Update: The referenced question did help me a lot, since there is a slight difference with the two questions, I want to add my understanding here.
The key is this sentence in the accepted answer of that question:
"If the GraphicalApplication requires a new method or change in semantics in the Rectangle class, then that affects the ComputationalGeometryApplication since they both "link" to the Rectangle library"
The keyword link reminds me the Rectangle is in a shared library. When it's changed by GraphicalApplication, the ComputationalGeometryApplication will automatically uses the new version of the Rectangle class. If the change to the Rectangle is not compatible with previous one, say, it adds some references of extra class in the constructor of Rectangle:
class Rectangle {
Rectangle() {
SomeExtraClass cls = new SomeExtraClass()
}
}
For ComputationalGeometryApplication, it will fail if we didn't rebuild it since it may not find the class SomeExtraClass when initialise the Rectangle class
I am making a maze that the player has to navigate with the mouse, but they lose when the hit a wall. I want to make sure the player has the mouse in the right place to start, so I am trying to switch to the game state once the mouse intersects with a square indicator on screen.
In the tutorial I was learning from, they did this:
public static class Point extends AbstractEntity {
public Point(double x, double y, double width, double height) {
super(x, y, width, height);
}
#Override
public void draw() {
glBegin(GL_POINTS);
glVertex2d(x, y);
}
#Override
public void update(int delta) {
// Blank
}
}
Point.setLocation(Mouse.getX(), 480 - Mouse.getY() - 1);
if(Maze1.intersects(Point)){
System.out.println("You would have lost");
}
I tried to do this:
case MAZE:
if(Maze1.intersects (Point) ){
state = State.GAMEOVER;
}
break;
I get the error, "Point cannot be resolved to a variable". Please help.
It looks like when you call Maze1.intersects you are passing the actual Point class rather than an instance of that class. This is why you get the "Point cannot be resolved to a variable" error. You need to create an instance of Point, call setLocation on that instance and then pass that into Maze1.intersects.
For your example to work I would either remove the argument on Maze1.intersects and have it access the Point class directly or change Point to it's no longer static, declare an instance of Point and pass that instance into Maze1.intersect.
Declaring the Point class as static does not mean you can pass the class into method, etc, like a regular variable as it's simply a way of sharing data and behaviour. Also, keep in mind that by declaring Point as static you are saying that there will only ever be one Point.
I would maybe consider dropping the static keyword and creating an instance of Point classed "startingPoint". You can then pass this into Maze1.intersects. Then if you need to determine if the player intersects with other "points" in the maze, then you can create other instances to represent those points.
In draw2d,How can I draw a figure without having any border?
How to implements the CustomBorder for rectangles to remove the border?
I know if we implement a class which extends Border, and in the paint method what should I do to remove the border?
Figures don't have a border unless you explicitly set one by calling setBorder(..). If you just want a blank figure that doesn't draw anything, then new Figure() will give you just that. There's no need to implement any custom borders or figures. If you are using a Rectangle then that's exactly what you will get: a rectangle; which is what you probably confused for a border.
You can disable the border with figure.setBorder(null); or you can put it in the constructor:
public static class BorderlessFigure extends Figure {
public BorderlessFigure() {
ToolbarLayout layout = new ToolbarLayout();
setLayoutManager(layout);
setBorder(null);
add(new Label("test"));
}
}
If you want a Border that does not paint anything you can extend org.eclipse.draw2d.AbstractBorder:
public class NoBorderBorder extends AbstractBorder {
#Override
public void paint(IFigure f, Graphics g, Insets i) { }
#Override
public Insets getInsets(IFigure f) {
return new Insets(0);
}
}
I don't know why would you do that though.
I am the new to the programming and now I have a query regarding the variable and properties which is "what is the difference between declaring public variable and public properties?". Could anyone explain me with some instances?
Alot of people have different views on what is the "right" way, just different coding standards. Personally i think public properties give you a little more control as in you can have some simple logic in the get or set methods. Where as public properties are fine if you just want some quick global variable.
There are some instances in .net when you have to have properties rather than public variables e.g. usually when binding to datasources etc.
for more info check this link:
codinghorror.com
To clarify a little of what John said, properties allow you to add limitations and logic to what you are doing.
For instance if I have a rectangle class
class Rectangle
{
private float mWidth;
private float mHeight;
private float mArea;
public float width
{
get
{
return mWidth;
}
set
{
mWidth = value;
mArea = mHeight*mWidth;
}
}
public float height
{
get
{
return mHeight;
}
set
{
mHeight = value;
mArea = mHeight*mWidth;
}
}
public float area()
{
return mArea;
}
}
So rect.width += 20;
will update both the width and area;
Obviously this is a dumb example, but you could have done this without the properties for width and height, using public variables instead and instead just used
public float area
{
get
{
return width*height;
}
}
This will give you the correct area if you say float x = rect.area, but will not let you say something like rect.area = 40.
There are many more in depth things that you can do with properties, like databinding, for instance, but if you are just starting to program, you will get to this later.
For right now, you can treat a property as a convenient method that does not require () and that can take or give a variable.
If it is doing nothing but getting and setting, its probably better off as a variable.
If it is doing alot of internal work, and affect a considerable portion of your class, it should probably be a method.
If it is a quick function
to validate input (float rotation{set{mRotation = value%360;}})
or a multiple check output ( bool isInMotion{get{return (!isTurning && ! isMoving)}}
propertys work well.
No rules are final of course.
I hope this gives you a basic understanding of properties vs variables, though as always there is plenty more to learn.
Good Luck!