Basic Learning of classes and methods in Ruby object-oriented programming, and ruby Object-Oriented Programming
Enable class and monkey Patches
In Ruby, the Class-defined method is no different from other statements and is executed in one row. Example:
class Example def method_1 puts "method 1" end end class Example def method_2 puts "method 2" end end
In this Example, when Class Example is defined for the first time, no Class named Example exists. Therefore, Ruby begins to define this Class. When this Class is defined later, ruby will find that this class already exists and return this class, instead of defining a new class.
Because of this feature, Ruby is born with the ability to open an existing class and dynamically modify its content, even if it is a standard class library class. For example, you can add a method to remove punctuation marks and special characters in the String class of the SDK: to_alphanumeric
class String def to_alphanumeric gsub /[^\w\s]/, '' end end “H&&^^ello”.to_alphanumeric #==>Hello
Then, all the String objects have the "to_alphanumeric" capability, which is generally referred to as open-type technology.
The open-class technology described above implies certain risks, especially when you use open-class technology in large systems to expand the standard class library, because many developers are extending the class, when the names of multiple extension methods are the same, the subsequent definition will always overwrite the previous one, resulting in the overall system crash, the industry calls this reckless modification method Monkey Patch for short ). Therefore, be cautious when using open technology.
Instance variables
In Ruby, instance variables are stored in objects, but they are irrelevant to the class of the object. When the instance variables of the object are assigned a value, the instance variables are generated, to put it bluntly, the instance variable is like a HashMap attached to an object. Each object can use its own HashMap, as shown in the following example:
class Person def name @name = "xianlinbox" end end p = Person.new puts p.instance_variables #==>nil p.name puts p.instance_variables #==>@name
Method
As an object, in addition to instance variables (also called attributes), you also need methods. However, in Ruby, the definition of methods is not in the object, but in the class of the object itself, because "objects of the same class must share the same method ". However, it cannot be said that the Class has a method called "method" because it cannot be used. method "to call this method, but to say that the Class has an instance method, this means that you must create an instance object of this Class and call this method through the instance object.
To define a class method, you must add the class name prefix when defining the method, as shown below:
class Person def Person.name @name = "xianlinbox" end end
The class itself is also an object
In Ruby, Class itself is also an object. All rules on objects apply to Class.
puts "hello".class #=> String puts String.class #=> Class puts Class.class #=> Class puts Class.instance_methods(false) #=> [:superclass,:allocate,:new] puts Class.instance_variables #=> nil
Class inheritance system
puts String.superclass #=> Object puts Class.superclass #=> Module puts Module.superclass #=> Object puts Object.superclass #=> BasicObjec puts BasicObject.superclass #=> nil
BasicObject is the root node of the inheritance system.
All classes are inherited from objects.
Class is an enhancement to the inheritance of the Module. The new () and allocate () methods are added to create instances.
Method Search and execution
Methods of objects in Ruby are defined in classes. to execute a method, you must first find this method. the method used by the Ruby compiler to find a method is, the first step is to find it in your own class. If it is not, you will find it along the class's ancestor chain (ancestors.
String.ancestors # => [String, Comparable, Object, Kernel, BasicObject]
Why is Comparable and Kernal appearing here? This is because of the Module mechanism. When a class includes a Module, compilation places this Module on the ancestor chain closest to this class, the String class includes the Comparable module, while the Kernal class is included by the Object class.
When a method is executed, a receiver is required, and the method will be executed in the receiver object. The receiver is the so-called self object. Generally, the self object is assumed by the last object that receives the method. In the definition of classes and modules (and out of the definition of any method ), the self object is composed of classes or modules.
Dynamic call Method
Generally, the method is called by "Object Name. method Name ", there is a cool feature in Ruby. You can use the send () method to take the name of the method you want to call as a parameter, so that when the code is running, the method to call is not determined until the last time. This technology is called Dynamic Dispatch ). This technology is very useful. For example, if a configuration file object exists in the project, it will be initialized according to the configuration file. during use, different users may set different values. The common practice is to determine the attribute corresponding to the key value of the attribute, and then call the corresponding set method. The Code is as follows:
config.name = v if isNameProperty?(k) config.password = v if isPasswordProperty?(k) config.port = v if isPortProperty?(k) ...
Looking at such a pile of code that looks like a brother, you can't help but get rid of them. If you use dynamic call methods, the code can be simplified as follows:
load_config('config.properties').each do |k, v| config.send("#{k}=", v) end
According to each obtained key value, the set Method of the corresponding attribute is called. The code is much refreshed, and the load method does not need to be modified to expand the config object in the future.
Dynamic definition method
In addition to dynamic calling methods, Ruby even supports dynamic defining methods. By using the Module # define_method () method, you can define a method by providing a method name and a block acting as the method body. Example:
class MyClass define_method :doubleString do |args| args * 2 end end t = MyClass.new puts t.doubleString("he") # => hehe
With this black magic, you can extract different parts of multiple similar methods as parameters, and then use a method to define all the methods.
Method_missing () method
Ruby is a dynamic language, and the compiler does not detect the behavior of method calls. Therefore, you can call a non-existent method. During running, a method_missing () method is called for calls that cannot find the corresponding method. This method is defined in the Kernal module, so each object inherits this method. In kernal, The method_missing () method throws a NoMethodError exception, which is the work done by the compiler.
However, we can override this method to make it interesting. For example, to create a Struct, you only need to assign a value to it to create a new attribute.
class MyStruct def initialize @attributes = {} end def method_missing(name, *args) attribute = name.to_s if attribute =~ /=$/ @attributes[attribute.chop] = args[0] else @attributes[attribute] end end end s = MyStruct.new s.weibo = "@xianlinbox" puts s.weibo # => @xianlinbox
From the caller's point of view, there is no difference from common methods, but the actual receiver has no corresponding Method. Ruby is called the Ghost Method ). In addition to customizing this method, you can also forward this method to another object. Of course, you can wrap your own logic before and after forwarding, this kind of processing technology is called Dynamic Proxy, which is similar to the Dynamic call mentioned above.
After method_missing is used to process the ghost method, all calls without methods will come here, which may cause some problems with incorrect information (you cannot see any prompts such as NoSuchMethod ), therefore, when using the method_missing scheme, you must limit the scope of use and call the super. if the method_missing method does not belong to this range, the system reports errors or errors.
Whiteboard and retention Methods
Each class has a bunch of methods inherited from the parent class. When using dynamic proxy technology, if a ghost method and a real method (you didn't expect the inherited method) in case of a name conflict, the latter wins, leading to system errors. Therefore, when using dynamic proxy technology, you can delete the vast majority of inherited methods in the proxy class to avoid name conflicts and delete the classes of inherited methods, this is the so-called whiteboard class (Blank Slate). There are two ways to delete class Methods: one is to call Module # undef_method, and the other is to call Module # remove_method.
In the Ruby Object class, some methods are used internally. If you re-define or delete them, Ruby may be inexplicably suspended. To prevent such a problem, ruby starts with "_" before these method names. These methods are called retention methods. When you try to modify these methods, Ruby will give a warning.