In a previous post I described the abstract components, in a correspondent abstract package, of the project of a Rules Validator in GitHub. In these lines I will complete the description of the project covering the concrete parts, the implementation classes of the abstract types.
For an architectural principle, I distinguish, and organize separately, the abstracts or type objects from classes or implementations. In this project, the implementation classes are in the namespace: Klod.Validation.Classes. In there, you will see a set of other namespace with concrete classes. Let’s see an overview:
Configuration. The configuration settings file (Config.settings) contains a map for the XML rules file elements and attributes. This abstraction of the XML decouples the concrete tags from their ulterior meaning. You can change the tags name or use a custom XML document type, as there is the possibility that the required elements and attributes could be «translated» to these settings.
Management. It only contains the RuleManager implementation. In this case the concrete implementation use another class within the project that will store the rules in an XML repository.
Mapping. In this namespace we find the XMLRuleMap and the XMLRulesRepository implementations. As you see, the implementation of the abstract RuleMap is an XML node encapsulating all the constraints (as child nodes), that the rules represent. The XMLRulesRepository is the concrete implementation of the abstract RulesRepository. It’s inner representation is of a Dictionary with all the rules as XML nodes with a unique key as identifier. This class will load the XML document of rules.
Rules. This namespace has the set of concrete implementations of the rules and constraints types. All these classes work with the Constraints and Rule abstracts. They are the responsible of finding the rule, check the constraints it describes, and return a boolean value whether the values are in comply or not with those constraints. The XMLConstraint class is another abstract, but simplifies the other concrete constraint classes implementation with the IsValid method.
Let’s see one of them. For example, the XMLExactConstraint should validate for strict values of equality, greater-than, less-than, greater-than-or-equal, less-than-or-equal, or not-equal. It uses the reflection capabilities of .NET Framework to the exact comparison under specified types. This last one aspect is very important and the pillar of all the comparisons. Different types can’t be compared for any of those constraints. The other classes, XMLOptionSetConstraint and the XMLRangeConstraint, cover the other possible comparisons that a simple rules validator must have.
As you see, most of the inner structure of rules and constraints are defined in the abstract types. This separation of concerns is a very important guideline in OOP, that propagates to other important principles: interface segregation, low coupling, programming to interfaces not implementations, indirection, polymorphism, etc. Also notice, to review, that the instantiation of these concrete classes are defined in factories under the abstract layer of types. With this configuration you can change the concrete implementation with the single change of their assembly and classe name in a configuration file.
My main objective in these two little articles is to show the architecture of a simple object-oriented project. Besides the language implementations, the structure and principles under the hood are the same. The main task in object-oriented programming is about to write algorithms over interfaces. The types in the abstract packages are the core of the solution. The implementations are a second part—a needed part, obviously—that could be delegated to other languages and frameworks.