介绍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方法的超类。

results matching ""

    No results matching ""