介绍private public protected的区别
private
#private
1.只能被隐式调用(处于实例方法中被调用),不能被显示调用(self.m或者obj.m调用)
class C
#错误调用方法
def one_method
self.private_method
end
#正确调用方法
def two_method
private_method
end
private
def private_method
end
end
C.new.one_method #这段代码会报出NoMethodError
C.new.two_method #正确
2.可以被子类继承,但是也不能被显式调用
class Demo
private
def demo
puts "this is the demo"
end
end
class Child < Demo
def child
demo
#self.demo, 这段代码进行显式调用,会出错
end
end
obj = Child.new
obj.child
public
1.public的类方法和实例方法可以被显示调用,也可以被隐式调用。
2.这个方法必须在所在的类或者实例化对象的作用域内。
#公开的类方法可以被显示调用,可以被隐式调用:
class DemoClass
class << self
def demo_method
puts "this is the class method"
end
end
DemoClass.demo_method #如期执行
demo_method #如期执行
end
demo_method #会报undefined method or variable
#上面的方法不在DemoClass这个作用域中,而在Object这个类的作用域中。
#公开的实例方法可以别显示调用,也可以被隐式调用:
class DemoClass
def demo_method
puts "this is the instance method"
end
end
obj = DemoClass.new
obj.demo_method
obj.instance_eval{ demo_method }
protected
1.不能被显式调用,但是可以被self调用
2.可以被子类继承,但是不能被显式调用,但是可以被self调用
3.可以被同一个类的其他对象直接调用
4.子类对象可以直接调用父类中已经定义的protected方法
1.不能被显式调用,但是可以被self调用
class Demo
def one
demo
end
def two
self.demo
end
protected
def demo
puts "this is the protected method"
end
end
obj = Demo.new
obj.demo #报错
obj.one #隐式调用
obj.two #可以被self调用
2.可以被子类继承,但是不能被显式调用,但是可以被self调用
class Demo
def one
demo
end
def two
self.demo
end
protected
def demo
puts "this is the protected method"
end
end
class Son < Demo
def three
demo
end
def four
self.demo
end
end
obj = Son.new
obj.demo #报错
obj.three #success
obj.four #success
3.可以被同一个类的其他对象直接调用
class Demo
def one(arg)
arg.demo
end
protected
def demo
puts "this is the protected method"
end
end
obj_one = Demo.new
obj_two = Demo.new
obj_one.one(obj_two)
4.子类对象可以直接调用父类中已经定义的protected方法
class Demo
def one(arg)
arg.demo
end
protected
def demo
puts "this is the protected method"
end
end
class SonOne < Demo
end
class SonTwo < Demo
end
obj = SonOne.new
obj.one(SonTwo.new)
effective ruby中关于protected的例子:通过protected方法共享私有状态
解决的问题:一个对象需要访问另外一个对象的内部状态
实例:比较两个点是否重合
class Widget
def initialize(x, y)
@x_axis = x
@y_axis = y
end
def overlapping?(other)
x1, y1 = @x_axis, @y_axis
x2, y2 = other.instance_eval{[@x_axis, @y_axis]}
[x1, y1] == [x2, y2]
end
end
obj = Widget.new(1,2)
p obj.overlapping?(Widget.new(1,2))
p obj.overlapping?(Widget.new(2,2))
可以通过上面的方式来实现比较两个点是否重复,但是上面用到的是instance_eval的元编程技巧。但是一般的做法是尽可能减少对该状态的直接访问,而是使用最小数量的访问方法(将状态的访问隐藏到私有方法中)。
通过使用protected方法来解决上面使用instance_eval的问题。下面介绍两种使用protected的情况,一种是两个对象是属于同一个类,第二种两个对象是有同一个定义protected方法的超类。
#两个对象属于同一个类
class Widget
def initialize(x, y)
@x_axis = x
@y_axis = y
end
def overlapping?(other)
x1, y1 = screen_coordinate
x2, y2 = other.screen_coordinate
[x1, y1] == [x2, y2]
end
protected
def screen_coordinate
[@x_axis, @y_axis]
end
end
obj = Widget.new(1,2)
p obj.overlapping?(Widget.new(1,2))
p obj.overlapping?(Widget.new(2,2))
#两个对象是有同一个定义protected方法的超类
class Father
def initialize(x, y)
@x_axis = x
@y_axis = y
end
protected
def screen_coordinate
[@x_axis, @y_axis]
end
end
class SonOne < Father
def overlapping?(other)
x1, y1 = screen_coordinate
x2, y2 = other.screen_coordinate
[x1, y1] == [x2, y2]
end
end
class SonTwo < Father
end
obj = SonOne.new(1,2)
p obj.overlapping?(SonTwo.new(1,2))
p obj.overlapping?(SonTwo.new(2,2))
总结:
1.通过protected共享私有状态
2.如果一个对象的protected方法要被显式调用,一般只有两种情况,一种是两个对象同属于一个类,第二种情况是两个对象的类有同一个定义protected方法的超类。