OOP: good class design

2019-01-30 12:35发布

问题:

My question is related to this one: Python tool that builds a dependency diagram for methods of a class.

After not finding any tools I wrote a quick hack myself: I've used the compiler module, I've parsed the source code into an Abstract Source Tree and I've walked it to collect dependencies between class methods. My script generated an input file for graphviz, which was used to generate a dependency graph that looks like this.

At this point I've got stuck. I've realized that I have no idea how to refactor the class to make it less complicated. I simply don't know what should I aim to. For example, in theory of relational databases there are a couple of simple rules that are used to bring a database to a normal form. What about some similar theory concerning the good class design (in terms of dependencies between its methods)? Is this topic covered somewhere so I could study it?

回答1:

We follow the following principles when designing classes:

  • The Single Responsibility Principle: A class (or method) should have only one reason to change.
  • The Open Closed Principle: A class (or method) should be open for extension and closed for modification.
  • The Liskov Substitution Principle: Subtypes must be substitutable for their base types.
  • The Interface Segregation Principle: Clients should not be forced to depend upon methods that they do not use. Interfaces should belong to clients.
  • The Dependency Inversion Principle: Abstractions should not depend on details. Details should depend on abstractions.

Edit: Design patterns are helpful in getting your code to comply with these principles. I have found it very helpful to understand the principles first and then to look at the patterns and understand how the patterns bring your code in line with the principles.



回答2:

It's often not possible to say whats 'correct' or 'wrong' when it comes to class design. There are many guidelines, patterns, recommendation etc. about this topic, but at the end of the day, imho, it's a lot about experience with past projects. My experience is that it's best to not worry to much about it, and gradually improve your code/structure in small steps. Experiment and see how some ideas/changes feel/look like. And it's of course always a good idea to learn from others. read a lot of code and analyse it, try to understand :).

If you wanna read about the theory I can recommend Craig Larmanns 'Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development' Amazon. He covers several parts of your question, gives some rough guidlines and shows them using an example application. I liked the book.

Could you upload your app somewhere? Perhaps on github or so, perhaps you could ask for some concrete advices.



回答3:

Design Patterns has become the defacto standard for good class design. Generally, each pattern has a particular use case, or scenario, which it applies to. If you can identify this in your code, you can use the pattern to create something that makes more sense, and usually has less dependencies.

Refactoring is the tool that you would use to accomplish these sweeping changes. A good IDE will help you to refactor.



回答4:

Try making each method easily unit-testable. I find this always drives my designs towards more readability/understandability. There are numerous OOAD rules -- SRP, DRY, etc. Try to keep those in mind as you refactor.



回答5:

I recommend the book "Refactoring" by Martin Fowler for tons of practical examples of iteratively converting poor design to good design.