It all depends on what your Shape is used for!
Short Answer
Robert Bräutigam's answer pretty much nails it. This is technically the best you can do. The Shape
class does not need to expose too much, definitely not all of its members. That is, if you are using the Shape
class. For all we know, you may be using the Shape
just for the purpose of representation, so you need all these properties to be visible somehow, somewhere. As far as this matter is concerned, we are dealing with an X-->Y problem, so we would need more details.
(Too?) Long Answer
Think of your application as the sales department of an international company. Employees are Shape
s (I know, I know, bear with me please). You people need to manage sales across the world. Unfortunately, all collaborating clients require interaction at their own location and communication in their own language (I'm sorry, your requirements correspond to such strict rules in the analogy)! Your given options, then, represent the following scenarios:
Option 1 (different class versions for a base Shape
class). An important sale comes up in Japan. In your sales department, nobody speaks Japanese. You need to (and do) find someone speaking Japanese (and is a seasoned salesperson) and send them to do the job! In short, your Option 1 corresponds to the sales department sending a person who speaks the language of the country you are selling to. This means you need to have as many people, as are the languages you may deal with. It doesn't matter much if an employee speaks 3 languages fluently...they cannot be in 3 places at the same time (ha, gotcha!).
Option 2 (only one Shape
class that is re-adapted in time). An important sales comes up in France. You need to go there, you have understood, by now, that top sales representatives fluent in the language you happen to need don't really come a dime a dozen. But the sales department does have great sales representatives. So, you arrange intensive courses in French, 1 month, just to get around the basics, customers will understand, they only care about the product, after all. Great sales representative born in the Netherlands now speaks some French. Next month, they need to speak some German too (oh, they already speak a lot of German, OK, make that Finnish).
If you understand where I'm getting at, neither option represents optimal resource management. The core problem your options are ignoring is that your application will have to survive in computers other than your own. Updating the source code every now and then means you have to compile your code again, deploy your code again and... are you really prepared to ship a new version of your entire application (OK, maybe only some module) every time a file format changes? Well, you may be, but this can quickly become a problem and is definitely not the greatest method to manage your resources.
Enter
- Option 3: Use a dictionary and/or a translator! Yes, hire someone from the country you will go to, either temporarily or permanently, they will mediate the communication and you will have much more success in much less time, with much fewer costs involved than the case of having your employees learn a new language every now and then (which is, well, not as easy as I may have made it seem above, frankly).
So, because your application will have to survive in a faraway land, you might want to use an additional "helper" dictionary. An "instructional" XML (sort of like a schema) map. This accompanying XML will contain information about what is parsed and what it ends up being assigned to. Check the following (naive) example in c#.NET:
Your classes:
class PropertyObject
{
//Stuff that MAY become necessary in the future.
Dictionary<string, string> m_Properties;
Dictionary<string, Type> m_PropertyTypes;
List<PropertyObject> m_NestedObjects;
}
class Shape : PropertyObject
{
//Necessary stuff that you KNOW should exist!
List<Feature> m_Features;
string m_Id;
//etc..
}
class Feature : PropertyObject
{
string m_Name;
Color m_Color;
}
Your XML:
<Shape>
<Id>0</Id>
<Features>
<Feature>
<Name>Name0</Name>
<Color>Color0</Color>
</Feature>
<Feature>
<Name>Name00</Name>
<Color>Color00</Color>
</Feature>
</Features>
</Shape>
Your potential map:
<xs:Shape>
<member id="Id" mapsTo="m_id" type="string"/>
<child id="Features" mapsTo="m_Features" type="Feature"/>
</xs:Shape>
<xs:Feature>
<member id="Name" mapsTo="m_name" type="string"/>
<!-- You might like to include full namespaces in some cases, for example... -->
<member id="Color" mapsTo="m_Color" type="System.Drawing.Color"/>
</xs:Feature>
Now any changes that may come up will necessitate that you only change the map, not the entire assembly/application. Consider the following example, a property comes up, useless to you, for the time being:
Your new XML:
<Shape>
<Id>0</Id>
<Gender>Female</Gender>
<Features>
<Feature>
<Name>Name0</Name>
<Color>Color0</Color>
</Feature>
<Feature>
<Name>Name00</Name>
<Color>Color00</Color>
</Feature>
</Features>
</Shape>
Your new Map:
<xs:Shape>
<member id="Id" mapsTo="m_id" type="string"/>
<child id="Features" mapsTo="m_Features" type="Feature"/>
<general id="Gender" type="string"/>
</xs:Shape>
<xs:Feature>
<member id="Name" mapsTo="m_name" type="string"/>
<!-- You might like to include full namespaces in some cases, for example... -->
<member id="Color" mapsTo="m_Color" type="System.Drawing.Color"/>
</xs:Feature>
And you will have taken the proper care to parse fields mapped as general
, for example, to the m_Properties
dictionary as simple strings, and their types (IF they exist, otherwise you can consider them strings). Someone else might prefer <ignore id="Gender"/>
so that you can just skip irrelevant stuff. Of course, if new types make their appearance, you may have to recompile, but there might be steps in that direction, which you could take to mitigate this problem as well. You can even store the entire XML within the object and parse it dynamically.
I am probably oversimplifying (or over-engineering) this, but, in general, I am trying to give you a conceptual direction. Look into any potentially already available tools and try to use an external mapping that is configurable in isolation. When your requirements change very often, instead of constantly Shape
-shifting to adapt, just introduce an additional layer of abstraction.