I'm using an AbstractFactory and polymorphism in my project and need to de-serialize xml to the correct type depending on a xml-element under the parent.
To be more specific (some pseudo code for explanation):
Public Interface IAnimal
Inherits IXmlSerializable
Public Property Name as String
Public Property Age as Integer
Public ReadOnly Property Type as AnimalType 'actually this is en Enum
End Interface
Public Interface IAnimalFactory
Public Function Breed(animalType as AnimalType) as IAnimal
End Interface
Public Class AnimalFactoryImpl
Implements IAnimalFactory
Public Function Breed(animalType as AnimalType) as IAnimal
Select Case animalType
case ...
return new Dog()
End Select
End Function
End Class
Public Mustinherit Class AnimalBaseImpl
Implement IAnimal
'do all the general stuff common to all animals here
Public MustOverride Sub Talk(words As String)
'implement IXmlSerializable.ReadXml here
'implement IXmlSerializable.WriteXml here
End Class
Public Class Dog
Inherits AnimalBaseImpl
'do dog specifics here
'implement Talk() here
End Class
Public Class Cat
Inherits AnimalBaseImpl
'do cat specifics here
'implement Talk() here
End Class
Public Class Cow
Inherits AnimalBaseImpl
'do cowspecifics here
'implement Talk() here
End Class
the xml that I need/have looks like his
<animal>
<animalType>Dog</animalType>
<name>Snoopy</name>
<age>62</age>
</animal>
It's easy to implement the WriteXml method. However, the ReadXml is giving me headaches.
So far I have included the de-serialization code in the parent object (e.g. Farm). I read all the elements from within the animal tag and then call animalFactory to create the correct type depending on the animalType.
I think that this is really not nice code and it really should go into the AnimalBaseImpl or the factory but I'm at a loss how to do this as new AnimalBaseImpl() is the first thing that will happen when de-serializing...
Any hints and trick welcome :-)
OK, after thinking for a bit more I came up with the solution myself. Quite easy once you get there ;-)
Since I'm using the Factory Pattern it's the Factory that needs to implement the deserialization. This is a creational pattern after all. This means, that ALL the creation methods should go into that factory. And deserializing is a creation method.
All i need to do is pass the XmlReader object to the factory and expect a return of whatever the Factory creates.
To stay with the above code example:
Public Interface IAnimalFactory
Public Function Breed(animalType as AnimalType) as IAnimal
Public Function XmlDeserializeAnimal(reader As XmlReader) As IAnimal
End Interface
Public Class AnimalFactoryImpl
Implements IAnimalFactory
Public Function Breed(animalType as AnimalType) as IAnimal
Select Case animalType
case ...
return new Dog()
End Select
End Function
Public Function XmlDeserializeAnimal(reader As XmlReader) As IAnimal implements IAnimalFactory.XmlDeserializeAnimal
'read all the tags here inkl. animalType
Dim returnAnimal as IAnimal = Me.Breed(animalType)
'set name and age here as per xml
Return returnAnimal
End Class
Now this can easily be called from withing the container object (e.g. Farm) which also implements IXmlSerializable. And all the container class needs to know of is the IAnimalFactory and the XmlDeserializeAnimal method.
Rather straight forward if you think about it (^_~)