I am quite new to the S.O.L.I.D. design principles. I understand their cause and benefits, but yet i fail to apply them to a smaller project which I want to refactor as a practical exercise to use the SOLID principles. I know there is no need to change an application that works perfectly, but I want to refactor it anyway so I gain design experience for future projects.
The application has the following task (actually a lot more than that but let's keep it simple): It has to read an XML file which contains Database Table/Column/View etc definitions and create an SQL file which can be used in order to create an ORACLE database schema.
(Note: Please refrain from discussing why I need it or why I don't use XSLT and so on, there are reasons, but they are off-topic.)
As a start, I chose to look only at Tables and Constraints. If you ignore columns, you could state it the following way:
A constraint is part of a table (or more precisely, part of a CREATE TABLE statement), and a constraint may also reference another table.
First, I will explain what the application looks like right now (not applying SOLID):
At the moment, the application has a "Table" class which contains a list of pointers to Constraints owned by the table, and a list of pointers to Constraints referencing this table. Whenever a connection gets established, the backwards connection will be established as well. The table has a createStatement() method which in turn calls the createStatement() function of each Constraint. Said method will itself use the connections to the owner table and referenced table in order to retrieve their names.
Obviously, this doesn't apply to SOLID at all. For example, there are circular dependencies, which bloated the code in terms of "add"/"remove" methods required and some large object destructors.
So there are a couple of questions:
- Should I resolve the circular dependencies using Dependency Injection? If so, I suppose the Constraint should receive the owner (and optionally the referenced) table in its constructor. But how could I run over the list of constraints for a single table then?
- If the Table class both stores the state of itself (e.g. table name, table comment etc) and the links to Constraints, are these one or two "responsibilities", thinking of the Single Responsibility Principle?
- In case 2. is right, should I just create a new class in the logical business layer which manages the links? If so, 1. would obviously no longer be relevant.
- Should the "createStatement" methods be part of the Table/Constraint classes or should I move them out as well? If so, where to? One Manager class per each data storage class (i.e. Table, Constraint, ...)? Or rather create a manager class per link (similar to 3.)?
Whenever I try to answer one of these questions I find myself running in circles somewhere.
The problem obviously gets a lot more complex if you include columns, indices and so on, but if you guys help me out with the simple Table/Constraint thing, I can maybe work out the rest on my own.