When using the “factory” pattern you should only be able to get a valid instance from the factory and NO other way. Thats kind of the point of the pattern – to reduce the number of points at which instances can be created. Normally in Xojo you might have a module with a method that can create instances, and its the only one allowed to do this. The constructors for the classes the factory method can create should be protected or private so they cannot be directly invoked using New outside the module.
Usually it might look something like (note this code will not compile)
Module People Public Interface IPerson Public Function GetName() as string End Interface Public Class Villager Implements IPerson Public Function GetName() as string return "Village Person" End Function Protected Sub Constructor() End Sub End Class Public Class CityPerson Implements IPerson Public Function GetName() as string return "City Person"; End Function Protected Sub Constructor() End Sub End Class Public Enum PersonType Rural Urban End Enum Public Function GetPerson(type as PersonType) as IPerson select case type case PersonType.Rural return new Villager() case PersonType.Urban return new CityPerson() else raise new UnsupportedOperationException end select End Function End Module
An alternative would be to not use an Interface for IPerson but to make it a base class – they end result is similar.
But, you cant do either in Xojo. At least not quite like my code above shows.
If you have a factory method in the module it cannot invoke their constructors. They are only callable by items in the class hierarchy. It has no special means to access the private or protected constructors of the classes it contains.
So you cant easily restrict construction to ONLY the factory method since what you really need is a “module” or “namespace” scope. And that doesn’t exist.
What you need to do is create an INTERFACE for the various classes in the namespace you intend to expose and make the classes in your namespace implement these interfaces. In addition you need to make the interfaces PUBLIC so they can be used outside the module. As well you need to make the classes that implement the interfaces PRIVATE so you can’t actually try and instantiate them outside the module. This has the unfortunate side effect of making it so you can only use the classes in the module via their interfaces. Remember what we really wanted was just to make it so the only legal way to get an instance was to use the factory.
Note that by having to do everything via an interface this means that “properties” are exposed by pairs of getter / setter methods. Fortunately in Xojo this has little semantic impact except that you have to write the code for it.
All code not in the module must use the interfaces as that’s all you have available.
But now because the classes in the module are PRIVATE you can put as many public constructors on them as you desire. They won’t be callable by anything outside of the module so instances cannot be created in ANY way except by calling the factory method in the module.
Module scope would help reduce this work needed to implement the Factory Pattern by making it possible to implement the module’s classes with “module” scoped constructors. This way you could have the factory return any of the parent or subclass instances and you could skip all the interfaces.
A sample of the initial implementation that doesnt work and the fixed version is here