I design new class, which contains the same function boolean isCellEmpty() at each level of abstraction. I have the Matrix class in the bottom of my class hierarchy. On the top I have GraphMainWindow class.
Where should I do checks (e.g. if (i >= 0, i < xCellsCount, j >= 0 and so…)?
Good question, wondered about it myself many times. Answer: In the lowest level. This way errors will never slip undetected.
You can still check for errors in higher level where an algorithmic process makes sense, but the lowest level is the most important.
There are some exceptions to this. For example, if the error is reported via a message that holds the applicatio and you expect many errors to occur in the lowest level. But these are not so common, and you can bend the above rule if you feel it disturbs you.