In the Java language, the launch mechanism is provided. Through the launch mechanism, this object can be constructed using strings to obtain all methods of the object (including private methods) and call private methods, you can change the value of a member variable (including a private member variable ).
Ruby is also an object-oriented high-level language. Of course it also provides a reflection mechanism. Today we will discuss the function of constructing class objects through class names.
1. Construct class objects using class names
Let's first look at the common structure:
Copy codeThe Code is as follows:
Module ModuleA
# The class name, later we will use it to create the corresponding object
CLASS_NAME_OF_WOOD = "ModuleA: Wood"
CLASS_NAME_OF_WOODDESK = "ModuleA: WoodDesk"
CLASS_NAME_OF_WOODCHAIR = "ModuleA: WoodChair"
Class Wood
Def initialize
@ Desc = "I am a primal wood"
End
Def say
Puts @ desc
End
End
Class WoodDesk <Wood
Def initialize
@ Desc = "I am a desk made of wood"
End
Def say_private
Puts "actually, I have some bugs but no public"
End
Public: say
Private: say_private
End
Class WoodChair <Wood
Def initialize
@ Desc = "I am a chair made of wood"
End
Def say_private
Puts "I Want get married with a WoodDesk ..."
End
Def smile
Puts "ha hah haha ...."
End
Public: say
Private: say_private,: smile
End
End
Defines a basic class Wood, which has two subclasses: WoodDesk and WoodChair. each subclass has a private method say_private.
We use the new output object to execute:
Copy codeThe Code is as follows:
# The normal initailze
Wood = ModuleA: Wood. new
Wood. say
Desk = ModuleA: WoodDesk. new
Desk. say
Chair = ModuleA: WoodChair. new
Chair. say
# Try call the private method
Puts "desk respond to say_private? # {Desk. respond_to? : Say_private }"
Desk. say_private if desk. respond_to? : Say_private
In the above Code, run the public method say, and then try to execute the private method say_private. check whether the result can be executed first, and the returned result cannot be executed, desk. respond_to? : Say_private: false:
Copy codeThe Code is as follows:
I am a primal wood
I am a desk made of wood
I am a chair made of wood
Desk respond to say_private? False
Well, now we use the reflection mechanism to construct the object and try to execute its private method.
We noticed that there are three constants in the module definition, which define the class name,
Copy codeThe Code is as follows:
# The class name, later we will use it to create the corresponding object
CLASS_NAME_OF_WOOD = "ModuleA: Wood"
CLASS_NAME_OF_WOODDESK = "ModuleA: WoodDesk"
CLASS_NAME_OF_WOODCHAIR = "ModuleA: WoodChair"
The following three variables are used to understand the Module. constants method.
The following code snippet is defined based on the above class:
Copy codeThe Code is as follows:
# Get all module constants
Obj_list = Array. new
Tmp_const_sym_list = ModuleA. constants
Tmp_const_sym_list.each do | sym |
Obj_list <ModuleA. const_get (sym)
Puts "calss =#{ sym. class}, value =#{ sym }"
End
We noticed ModuleA. constants. This method is in the Module, and its function is to return the Symbol object of all constants in the Module. We can see the result output:
Copy codeThe Code is as follows:
Calss = Symbol, value = CLASS_NAME_OF_WOOD
Calss = Symbol, value = CLASS_NAME_OF_WOODDESK
Calss = Symbol, value = CLASS_NAME_OF_WOODCHAIR
Calss = Symbol, value = Wood
Calss = Symbol, value = WoodDesk
Calss = Symbol, value = WoodChair
The results show that the three defined constants and class names are returned. Note: constants in Ruby are defined constants (variables) and Class names. Note that they are all Symbol objects ..
However, if we need to construct a class object based on the class name, the three constants are useless and need to be deleted. We use regular expressions to match names. Modify the above Code:
Copy codeThe Code is as follows:
# Get all module constants
Sym_list = Array. new
Tmp_const_sym_list = ModuleA. constants
Tmp_const_sym_list.each do | sym |
Puts "calss =#{ sym. class}, value =#{ sym }"
Sym_list <ModuleA. const_get (sym) if/^ Wood \ w */= ~ Sym. to_s
End
Sym_list <ModuleA. const_get (sym) if/^ Wood \ w */= ~ Sym. to_s, only save the symbol starting with Wood, so that we can filter out the three constants.
After the class name is found, the object is constructed:
Copy codeThe Code is as follows:
# Create object from symbol
Obj_list = Array. new
Sym_list.each do | sym |
Obj = sym. new
Obj_list <obj
Puts "create the object: # {obj }"
End
Begin
Obj_list.each do | wood |
Wood. say
End
Call the new method of Symbol to construct the next object (sym. new). Then we call the say method of the object:
Copy codeThe Code is as follows:
Create the object :#
Create the object :#
Create the object :#
I am a primal wood
I am a desk made of wood
I am a chair made of wood
We have achieved our expected results.
Ii. operating member variables and private methods
All the students who have used Java reflection know that when an object is available, the member variables and private methods will be ignored.
The same is true in Ruby.
First, let's look at the example of operating member variables. We try to change the value of a member variable. (The Code of the previous Article)
Copy codeThe Code is as follows:
# Manpulate instance variables
First_wood = obj_list.first
First_wood.instance_variables.each do | var |
# Get the instance variable
Puts "class of var =#{ var. class}, value of var =#{ var }"
Var_value = first_wood.instance_variable_get (var)
Puts "class of var_value =#{ var_value.class}, value of var_value =#{ var_value }"
# Set the new value of instance varialbe
First_wood.instance_variable_set (var, var_value + "... and I was changed .")
First_wood.say
End
1. first_wood.instance_variables.each. We get a Wood object and call its instance_variables method to get the name of all member variables (Symbol object ).
2. Then, call the first_wood.instance_variable_get method of the object and pass the member variable name to obtain the member variable object.
3. Finally, we use first_wood.instance_variable_set to change the value of this member variable.
Code running result:
Copy codeThe Code is as follows:
Class of var = Symbol, value of var = @ desc
Class of var_value = String, value of var_value = I am a primal wood
I am a primal wood... and I was changed.
Let's call the private method again:
Copy codeThe Code is as follows:
# Call private method
Last_wood = obj_list.last
Last_wood.method (: say_private). call
If you know the Method name and call last_wood.method to pass in the Method name, you can get a Method object and then call the call Method of the Method object. The result is the output content of the private Method:
Copy codeThe Code is as follows:
I Want get married with a WoodDesk...
In common scenarios, member variables cannot be modified or private methods can be called, because this violates the object-oriented encapsulation principle. In what scenarios is reflection useful? In my personal experience, I think it is useful in two areas:
1) unit test.
2) Aspect-Oriented Programming.
Both scenarios require calling a private method or replacing the value of a member variable.
What do you think?