Embracing the DRY principle in XML
We have a product where each customer has an XML config file containing sets of UI options and sub-options. For example, one type of users (call them A's) have one set of options and another type of users (B's) have a different set of options.
The problem I have is that A and B share most of the options, though sometimes when they share an option, one or more of the sub-options differ.
Now we're 开发者_开发知识库getting customers with, instead of two types of users, 30 types of users, and that customer's config files are bloated with the same piece of information repeated up to 30 times, creating a maintenance nightmare for development.
Which ways would you recommend to apply the DRY principle to this situation?
You need to implement a form of inheritance, just like inheritance in object-oriented programming languages or CSS, in which you start with a set of common options, and then allow it to be overridden by other options in more specific sets.
You establish a hierarchy of sets of options, starting at the top with options common to all users, then sets of options that you have identified as being common to many types of users, and finally the user-specific options. This needs to be represented as a tree in your XML configuration file, by your giving each set of options a name and a parent. At the bottom of the tree are the sets of options that are named after the specific types of users (As, Bs etc.).
In your program you need to read this file and assemble the tree in memory. Then, move through it from top to bottom collecting the options and overriding them as you go. When you reach the user-specific options at the leaves of the tree and perform the last overrides, you are finished.
When you are factoring your options, you may find that some sets need to have more than one parent, because they combine options from more than one set. If this is the case, your tree becomes a DAG, and you need to topologically sort it before you traverse it.
I realise that this is a complex solution, but I can assure you that it is the most flexible way of dealing with multiple configurations that have common elements. I have implemented it successfully in order to configure several e-commerce Web sites that used the same back-end.
The same way that Ant does: each unique piece of configuration information can be given an ID, and can be referred to via that ID.
Example (from the Ant user manual):
<project ... >
<path id="project.class.path">
<pathelement location="lib/"/>
<pathelement path="${java.class.path}/"/>
<pathelement path="${additional.path}"/>
</path>
<target ... >
<rmic ...>
<classpath refid="project.class.path"/>
</rmic>
</target>
<target ... >
<javac ...>
<classpath refid="project.class.path"/>
</javac>
</target>
</project>
精彩评论