Rules:
- Program to an interface not an implementation
- Favour object composition over class inheritance
Common redesign reasons:
- Creating an object class specifically, favour instead indirect methods. Commiting yourself to a particular implementation only hinders e.g. porting and changing things.
- Dependence on specific operations, when requesting from external entities don't directly do it. You're locking yourself into only one way of getting that information.
- Dependence on hardware and software platform, limit the dependence on the system itself directly. Instead use platform independent abstractions to limit porting issues.
- Dependence on object representations or implementations, how a peice of data is stored or used should not be directly accessible. A common interface should be instead perferred so any changes in the implementation itself can hide how its stored (to prevent user code to be dependent on how the code implementation works).
- Algorithmic dependencies, if an algorithym is likely to be changed it should be isolate so that it can be dealt with as little as user code to be needed to be modified when it changes as possible.
- Tight coupling, when classes care about other classes existing too much. It forces having to have all or nothing code bases where the porting to other systems are hard to do.
- Extending functionality by subclassing, use composition instead of inheriting clsses. Inheriting classes means understanding the parent class and how it works which may not be easy. If needed sub classing to make it easy to work with is possible and then use with composition to extend the program.
- Inability to alter classes conveniently, having the need to alter a class where the source may not be available or inedible means the design to get it were unacceptable. In such a factory should be implemented and then extended upon to provide the functionality required.