Ruby Programming/Syntax/Classes
Classes are the basic template from which object instances are created. A class is made up of a collection of variables representing internal state and methods providing behaviours that operate on that state.
在个体导向(object-oriented)的世界中,每个事物,如太阳、月亮、文件、目录、储存体、你、我、他等等,都视为独立个体(objects)。我们又将这些独立个体按其属性、行为抽象化地分门别类,于是有了各种类(classes)。我们称归属于某一类的个体为该类的实例(instance),例如我家养的小黄狗,就是狗类的一个实例。在某些程式语言中,个体与实例的差别不明显,初学者常分不清两者意义。但是,在 Ruby 之中一切都是个体,举凡字面值、函数及类别等等,都是个体;而实例仅仅指我们向 Ruby 要求配置的某一类别之实体化的个体,而不指涉类、字面值等个体。
定义类别
[编辑]Ruby 以关键字 class
定义'类(Class)'的内容。类的名称必须按 camel 惯例命令,此为基于英文系统之命令惯例:以英文字(word) 组成名称,每个字的首字母皆作大写,而且每个字必须相接不可以分隔字元分开。例如 'MyClass', 'BasicSocket', 'DateTime'。类的定义内容包含方法与类别变数,以关键字 end
结束定义。
语法:
class
類別名稱<
父類別@@
類別變數名def
方法名 #方法的程式區塊 endend
我们可以一个即有的类为基础衍生新类,并定义新的方法;亦可直接定义新类而不继承即有的类。一个类的定义内容可以完全空白,没有任何方法或类别变数。
范例:
class MyClass def some_method end end
实体变数(Instance Variable)
[编辑]实体变数以@运算子开头,每个实体变数都必须在成员函式内设定值才有效,不然会回传nil,请看下面的范例:
Example:
class MyClass @one = 1 def do_something @one = 2 end def output puts @one end end instance = MyClass.new instance.output instance.do_something instance.output
结果是:
nil 2
This happens (nil in the first output line) because @one defined below class MyClass is a class instance variable(?), whereas @one defined inside do_something method is a variable of object instance. They are two distinct variables and the first is accessible only in a method of a class(?).
类别变数(Class Variable)
[编辑]Class variables are accessed using the @@ operator. These variables are associated with the class rather than any object instance of the class and are the same across all object instances. (These are the same as class "static" variables in Java or C++).
Example:
class MyClass @@value = 1 def add_one @@value= @@value + 1 end def value @@value end end instanceOne = MyClass.new instanceTwo = MyClass.new puts instanceOne.value instanceOne.add_one puts instanceOne.value puts instanceTwo.value
Outputs:
1 2 2
Be careful when you use class variables though. They can sometimes lead to an additional
debug time, thus I'd advise you to only use them when it is absolutely necessary
to use them.
类别方法(Class Method)
[编辑]Class methods are declared the same way as normal methods, except that they are prefixed by self
followed by a period. These methods are executed at the Class level and may be called without an object instance. They cannot access instance variables but do have access to class variables.
Example:
class MyClass def self.some_method puts 'something' end end MyClass.some_method
Outputs:
something
实体化(Instantiation)
[编辑]An object instance is created from a class through the a process called instantiation. In Ruby this takes place through the Class method new
.
Example:
anObject = MyClass.new(parameters)
This function sets up the object in memory and then delegates control to the initialize function of the class if it is present. Parameters passed to the new function are passed into the intialize
function.
class MyClass def initialize(parameters) end end
可见度宣告(Visibility)
[编辑]所有的方法默认的都是公开的,可被所有对象调用。需要的时候可以用 public, private 和 protected 加以限制。有趣的是这些并不是关键字,而仅仅是对类本身进行操作方法,他们可以动态的改变方法的可见度。
http://www.rubycentral.com/book/ref_c_module.html
私有 (private)
[编辑]简单的例子:
class Example def methodA end private # all methods that follow will be made private: not accessible for outside objects def methodP end end
如果 private 没有跟任何参数, 它后续的所有方法都变成私有。如果有参数,则指明的方法变为私有。
Named private method example:
class Example def methodA end def methodP end private :methodP end
Here private was invoked with an argument, altering the visibility of methodP to private.
注意如果是类的方法(静态方法,按照 def ClassName.method_name 声明的), 则需要使用另外的方式: private_class_method。
常见的用法是把 new 方法设定为私有,这样就可以实现唯一的实例。
class SingletonLike private_class_method :new def SingletonLike.create(*args, &block) @@inst = new(*args, &block) unless @@inst return @@inst end end
More info about the difference between C++ and Ruby private/protected: http://lylejohnson.name/blog/?p=5
One person summed up the distinctions by saying that in C++, “private” means “private to this class”, while in Ruby it means “private to this instance”. What this means, in C++ from code in class A, you can access any private method for any other object of type A. In Ruby, you can not: you can only access private methods for your instance of object, and not for any other object instance (of class A).
Ruby folks keep saying "private means you can not specify the receiver". What they are saying, if method is private, in your code you can say:
class AcessPrivate def a end private :a # a is private method def acessing_private a # sure! self.a # sure! same as above, because "self." prefix was implicit there other_object.a # nope, a is private, you can't get it (but if it was protected, you could!) end end
Here, "other_object" is the "receiver" that method "a" is invoked on. For private methods, it does not work. However, that is what "protected" visibility will allow.
Public
[编辑]Public is default accessibility level for class methods. I am not sure why this is specified - maybe for completeness, maybe so that you could dynamically make some method private at some point, and later - public.
In Ruby, visibility is completely dynamic. You can change method visibility at runtime!
Protected
[编辑]Now, protected deserves more discussion. Those of you coming from Java (or C++) background, you know that "private" means that method visibility is restricted to the declaring class, and if method is "protected", it will be accessible for children of the class (classes that inherit from parent).
In Ruby, private visibility is what protected was in Java. Private methods in Ruby are accessible from children. This is a sensible design, since in Java, when method was private, it rendered it useless for children classes: making it a rule, that all methods should be "protected" by default, and never private. However, you can't have truly private methods in Ruby; you can't completely hide a method.
The difference between protected and private is subtle. If a method is protected, it may be called by any instance of the defining class or its subclasses. If a method is private, it may be called only within the context of the calling object---it is never possible to access another object instance's private methods directly, even if the object is of the same class as the caller. For protected methods, they are accessibe from objects of the same class (or children).
So, from within an object "a1" (an instance of Class A), you can call private methods only for instance of "a1" (self). And you can not call private methods of object "a2" (that also is of class A) - they are private to a2. But you can call protected methods of object "a2" since objects a1 and a2 are both of class A.
Ruby FAQ gives following example - implementing an operator that compares one internal variable with variable from another class (for purposes of comparing the objects):
def <=>(other) self.age <=> other.age end
If age is private, this method will not work, because other.age is not accessible. If "age" is protected, this will work fine, because self and other are of same class, and can access each other's protected methods.
To think of this, protected actually reminds me of the "internal" accessibility modifier in C# or "default" accessiblity in Java (when no accessibility keword is set on method or variable): method is accessible just as "public", but only for classes inside the same package.
实例变数存取子(Instance Variable Accessor)
[编辑]Note that object instance variables are not really private, you just can't see them. To access an instance variable, you need to create a getter and setter.
Like this (no, don't do this by hand! See below):
class GotAccessor def initialize(size) @size = size end def size @size end def size=(val) @size = val end end # you could the access @size variable as # a = GotAccessor.new(5) # x = a.size # a.size = y
Luckily, we got special functions to do just that: attr_accessor, attr_reader, attr_writer.
attr_accessor will give you get/set functionality, reader will give only getter and writer will give only setter.
Now reduced to:
class GotAccessor def initialize(size) @size = size end attr_accessor :size end # attr_accessor generates variable @size accessor methods automatically: # a = GotAccessor.new(5) # x = a.size # a.size = y
继承(Inheritance)
[编辑]一个类可以自'基础类(base class)' - 或称'父类(parent class)'或 'supperclass' - 继承方法与类别变数。Ruby 不支持'多重继承',故一个类只有一个基础类。新的类可以再衍生更底层的类,而衍生的类总是拥有比基础类更丰富的方法,代代相承形成类别树而逐渐创造出行为丰富的世界。
在 Ruby 中,方法的预设可见度为 public
,我们可以指定可见度为 private
。在继承行为中,衍生类不会承继基础类的 private 方法。
范例:
class ParentClass def a_method puts 'b' end end class SomeClass < ParentClass # < means inherit (or "extends" if you are from Java background) def another_method puts 'a' end end instance = SomeClass.new instance.another_method instance.a_method
输出:
a b
If your class overrides a method from parent class (superclass), you still can access the parent's method by using 'super' keyword.
class ParentClass def a_method puts 'b' end end class SomeClass < ParentClass def a_method super puts 'a' end end instance = SomeClass.new instance.a_method
Outputs:
b a
(because a_method also did invoke the method from parent class).
If you have a deep inheritance line, and still want to access some parent class (superclass) methods directly, you can't. super only gets you a direct parent's method. But there is a workaround! When inheriting from a class, you can alias parent class method to a different name. Then you can access methods by alias.
class X def foo "hello" end end class Y < X alias xFoo foo def foo xFoo + "y" end end puts X.new.foo puts Y.new.foo
Outputs
hello helloy
类别混成(Mix-in)
[编辑]老子有云:'有物混成,先天地生'。在 Ruby 之中,也有着混成(mix-in)的概念。Ruby 可以将行为自类抽离出来,使其成为与类或实例无关的抽象化行为。我们可以再将这些抽象化行为混成一个新的类,或令一个类包含更多种行为。
Ruby 利用模组(modules)组织管理抽象化行为、变数和类,其用途类似名称空间(namespaces)。虽然模组有点像类,但它不是类,所以你不能实体化一个模组,也不能在其中使用 self
。 Ruby 以关键字 module
定义模组,除此之外的语法与类的定义相同:
module MixAlot def say_what? "hello" end end
Ruby 允许我们在类中包含模组,或者说将模组混入类,使类含有更多行为。在类的内容中,以关键字 include
包含模组即可混成。
class MC include MixAlot # ... method say_what? is available here! end
如果你的模组置于另一份文件中,在 include
模组之前必须先以 require 叙述载入模组文件。
Ruby类别中介模组(Class Meta-Model)
[编辑]In keeping with the Ruby principle that everything is an object classes are themselves instances of the class Class. They are stored in constants under the scope of the module in which they are declared. A call to a method on an object instance is delegated to a variable inside the object that contains a reference to the class of that object. The method implementation exists on the Class instance object itself. Class methods are implemented on meta-classes that are linked to the existing class instance objects in the same way that those classes instances are linked to them. These meta-classes are hidden from most Ruby functions.