Given a class hierarchy as follows:
class A
def initialize(param)
if param == 1 then
#initialize and return instance of B
else
#initialize and return instance of C
end
end
end
class B < A
end
class C < A
end
Is it possible to actually initialize and return an instance of B
or C
when initializing A
? I.e. my_obj = A.new(param)
would result in my_obj
being an instance of class B
or C
depending on the value of param
, which gets checked in A.initialize(param)
.
In my usecase its only known at runtime which subclass (B
or C
) to use and the parent class (A
) is basically never really used.
I thought it might be a good idea to move the logic of deciding whether B
or C
into their common ancestor.
If this is not possible (or bad style), where should I put the check of param
and the decision which class to initialize?
Instead of overriding new, you could create a
self.instantiate
method which would then call.new
.The thing is, the return value of
initialize
is ignored. here's what happens when you callA.new
:new
calls a special class method calledallocate
-- this returns an empty instance of the classnew
then callsinitialize
on the object returned byallocate
, and returns the objectTo do what you want to do, you need to override
new
and make it do what you want:There is something else to consider though. If
A
is never really used on its own, you should be using some sort of factory method, or, just a simple if statement. Eg:The design really depends on what you are using them for. When you, for example, have a class that could be used to handle multiple versions of something, for example, HTML, you could have a main class
HTMLParser
which overrodenew
and could return any of its subclasses:HTML1Parser
,HTML2Parser
,HTML3Parser
,HTML4Parser
, andHTML5Parser
.Note: You have to override the
new
method to the default in the sub-classes to prevent infinite looping:You're breaking a fundamental OO principle here -- classes should know nothing about their subclasses. Of course, sometimes principles should be broken, but there's no apparent reason to do it here.
A far better solution is to shift the instantiation logic to a factory method in a separate class. The factory method takes the same arguments as the A's initializer above, and returns an instance of the appropriate class.