This is a design problem. I am confused how to use composition in the below problem scenario:
class A(object):
def __init__(self,a,b,c=None,d=None,e=None,f=None):
do_something()
def result():
#Does some basic processing
class B(A):
def __init__(self,a,b,e):
super(B,self).__init__(a,b,e=e)
self.some_variable = True
def result(self):
#Does some advanced processing
class C(A):
def __init__(self,a,b,c=None,d=None,e=None):
super(C,self).__init__(a,b,c,=c,d=d,e=e)
self.b = B(a,b,e=e)
The problem with this is that class C creates a class B object as composition but B calls __init__ for its super class A again. So I want to avoid calling the constructor of class A again by class C.
Makes sense to extend C from A, since C is extension of A. And C access the functionality of B via composition.
I dont know python, but of you want i can share Java code that does it.
class C(A):
def __init__(self,a,b,c=None,d=None,e=None):
super(C,self).__init__(a,b,c,=c,d=d,e=e) # assuming it is inheritance.
self.b = B(a,b,e=e) # assuming it is composition
def result(self):
self.b.result #Does some advanced processing
# access functionality of B, via object (composition)
def other_functions_2(self):
self.functionality2 # can access functionality of A, via inheritance
Related
I have a module that provides logging functionality. Some classes extend it, others include it. As part of the logging, I pass in a class name.
If I do this:
global_logger.call(level, self, msg)
It could log either:
WARN -- Some::Class: some msg
OR
WARN -- #<Some::OtherClass:0x00007fdc04907710>: some msg
based on if the module was extended or included. I can call self.class instead, but then the the other one turns into Class.
Is there a way to get a class name(without the #<...:0x00007fdc04907710>), given that you don't know if self is a class or an instance?
There are a number of things you could do, but one of the easiest is probably to see if the passed object is a class before trying to extract other information about it. For example:
Object.kind_of? Class #=> true
Object.new.kind_of? Class #=> false
You can then decide what methods are appropriate to call based on whether or not it's a class. For example:
p Object.new.class.name #=> "Object"
P Object.name #=> "Object"
We know that, for a given module M, you can determine if a class C has included M by writing
C.included_modules.include?(M)
To determine if a class C has extended M you may execute
C.singleton_class.included_modules.include?(M)
because extending a module to a class is equivalent to including the same module to the class' singleton class.
See Module#included_modules and Object#singleton_class.
Here is an example.
module M
def m; end
end
class C
extend M
end
a = C.singleton_class.included_modules
#=> [M, Kernel]
a.include?(M)
#=> true
I have a library that I would use in an app by using a class that wraps the library object in a new class by inheriting from it and adding a few instance variables. I can change the library code if need be. Here is the problem:
class A
def process_it
# Make a new instance
aa = self.class.new
do_something_to(aa)
end
def do_something_to(item)
item
end
end
class B < A
def initialize(extra = "Default extra")
#extra = extra
super()
end
def extra
#extra
end
end
# I want B to inherit A's methods, like #process_it but:
b = B.new("Non-default extra")
puts b.process_it.extra => Default extra
The output should have been "Non-default extra" and the problem is that, in the parent class I call self.class.new but can pass no parameter to it to set #extra. In the call, self.class is B, the inherited class, but when I write the parent class library, A, I cannot predict what, if any parameters, should be passed to self.class.new. Indeed, I might have class C < A with different parameters for initialize.
Is there a proper way to write the code in library A to instantiate a new instance of the self class that takes possible parameters into account?
Will #dup work for you? Instead of aa = self.class.new, change it to aa = self.dup
I am trying to create simple class with ability to register derived classes for creation from base class. However I cannot find a good way to encapsulate this functionality from descendants.
Class variables looks for me a bad idea because they available everywhere in inheritance chain. So I try do something with class instance variables. Perfectly it will be that all class methods will be inaccessible except register_as
class A
#registered = {}
class << self
def register_as(name)
A.registered[name] = self
end
def known
A.registered
end
protected
attr_accessor :registered
end
def helpful_method
end
end
class B < A
class << self
def reg_trash
A.registered[:trash] = :trash
end
end
B.register_as :b
end
B.reg_trash
p A.known
However registered is still accessible from B class.
Currently looks like the only one possible option is to split A class to dedicated Factory class and A class will hold only helpful instance methods.
Maybe it is possible to do something via .inherited and .undef_method, isn't it?
Maybe it is possible to do something via .inherited and .undef_method, isn't it?
Yes, it is possible. But the idea smells, as for me - you're going to break substitutability.
If you don't want the "derived" classes to inherit the behavior of the parent, why do you use inheritance at all? Try composition instead and mix in only the behavior you need. For example, something like this could work (very dirty example, but I hope you got the idea):
class A
module Registry
def register_as(name)
A.register_as(name, self)
end
end
#registered = {}
def self.register_as(name, klass)
#registered[name] = klass
end
def self.known
#registered
end
end
class B
extend A::Registry
register_as :b
end
class C
extend A::Registry
register_as :c
end
A.known # => {:b => B, :c => C}
I have classes A and B, each with methods a and b respectively, like below.
class A
def a
#I want to get the object which calls this method
#caller = B
end
end
class B
def initialize
#to_call = A.new
end
def b
#to_call.a
end
end
B.new.b
How can I return B that calls a so that I can use methods of B inside A?
I have a class Board, which Game classes use to play. The board class has a method interact that gets user input either with gets.chomp or STDIN.getc to simulate guessing games or games which use arrow keys. The game class calls the interact method to begin playing the game, and sends it a block that handles the way the game is played. Each game has its own set of rules, therefore each game class has a method that displays its rule book to the user. Within interact, when the user enters "-rules", I want the board class to return the class that called its interact method and store it in a variable caller. With the caller variable defined, I want to use caller.rule_book to display the rules of the game class that called the board's interact method.
I don't know a way you you could do it, besides using the source's location (caller_locations), but I'd advise not to follow this path. Too much indirection often leads to code extremely hard to debug. It's much simpler and readable to simply pass the context (in this case, self, or the properties needed for the computation) as an argument:
class A
def initialize(context)
#context = context
end
def a
# Do something with #context
end
end
class B
def initialize
#to_call = A.new(self)
end
def b
#to_call.a
end
end
B.new.b
I can't figure out how to initialize a class from a parent class variable. I'm trying to accomplish this:
x = A::B.new('my string')
myObject = x::C.new(**params)
and the program I'm calling is organized similar to:
module A
...<stuff>...
class B
...<stuff>....
class C < B
...<stuff>...
end
end
end
I want to initialize the class C after initializing the parent class B. That way, I can have access to class B's variables and methods from class C.
When I try to execute my program, I get:
"#<A::B:0x...............>" is not a class/module (TypeError)
Can anyone point me in the right direction for initializing nested classes like this?
You can't construct an instance from an instance - the whole module hierarchy is only applicable to modules and classes. Since x is neither, the parser has no idea what :: is supposed to do.
The idea behind nested classes is that they are namespaced within the parent class, no more, no less. In effect, class B acts like a module prefix to class C, but there's no inherent relationship between them (by being nested alone; you do inherit C from B in your example, which is what gives you the relationship), and certainly not between an instance of B and the class C
Instead, I would recommend constructing a C directly with 'my string', then calling #super in the initialize method, like so:
myObject = A::B::C.new('my string', **params)
and in the implementation:
module A
class B
def initialize(some_string)
#some_string = some_string
end
class C < B
def initialize(str, params)
super(str)
...
end
end
end
end
As the error message suggests, the namespace operator :: can only be applied to a class/module. If x were the class A::B, then x::C should work. It does not make sense to apply ::C on an instance of A::B.
You need to apply the :: to x's class, not x itself. So you just need a call to the class method:
x = A::B.new('my string')
myObject = x.class::C.new(**params)
For example, this sort of thing:
module A
class B
class C
end
end
end
pancakes = A::B.new
eggs = pancakes.class::C.new
puts pancakes.inspect
puts eggs.inspect
gives you something like this:
#<A::B:0x007faea90b6a58>
#<A::B::C:0x007faea90b6a30>