Ruby 객체지향


Ruby는 순수 객체 지향 언어입니다. Ruby의 모든 것은 객체 형태로 나타납니다. Ruby의 모든 값은 객체입니다. 가장 원시적인 것조차도 객체입니다. 문자열, 숫자, 심지어 true와 false도 객체입니다. 클래스 자체도 Class 클래스의 인스턴스인 object입니다. 이 장에서는 객체 지향 Ruby와 관련된 모든 주요 기능에 대해 설명합니다.

클래스는 데이터 표현과 메소드를 결합하여 데이터를 깔끔한 패키지로 구성하는 객체의 형태를 지정하는 데 사용됩니다. 클래스의 데이터와 메서드를 클래스의 멤버라고 합니다.

Ruby 클래스 정의

클래스를 정의하면 실제로 데이터 유형의 청사진을 정의하는 것입니다. 이는 실제로 데이터를 정의하는 것이 아니라 클래스 이름이 무엇을 의미하는지, 즉 클래스의 객체가 무엇으로 구성될지, 객체에 대해 어떤 작업을 수행할 수 있는지를 정의합니다.

클래스 정의는 class 키워드로 시작하고 그 뒤에 클래스 이름이 오고, 마지막으로 end로 구분되어 클래스 정의를 종료합니다. 예를 들어 키워드 클래스를 사용하여 Box 클래스를 다음과 같이 정의합니다.

class Box
   code
end

관례상 이름은 대문자로 시작해야 합니다. 여러 단어가 포함된 경우 각 단어의 첫 글자는 대문자로 표시되지만, 대문자는 없습니다. 여기에 구분 기호를 입력하세요(예: CamelCase).

Ruby 객체 정의

클래스는 객체의 청사진을 제공하므로 기본적으로 객체는 클래스를 기반으로 생성됩니다. new 키워드를 사용하여 클래스의 객체를 선언합니다. 다음 문은 Box 클래스의 두 개체를 선언합니다.

box1 = Box.new
box2 = Box.new

initialize 메서드

initialize 메서드는 클래스의 생성자인 표준 Ruby 클래스 메서드이며 다른 개체 지향 프로그래밍의 constructor와 동일하게 작동합니다. 유사한 언어. 초기화 메소드는 객체를 생성하는 동안 일부 클래스 변수를 초기화하려고 할 때 유용합니다. 이 메소드는 일련의 매개변수를 취하며 다른 Ruby 메소드와 마찬가지로 이 메소드를 사용할 때 아래와 같이 def 키워드를 앞에 배치해야 합니다.

class Box
   def initialize(w,h)
      @width, @height = w, h
   end
end

인스턴스 변수

인스턴스 변수는 클래스 속성입니다. 클래스가 객체를 생성하면 객체의 속성이 됩니다. 각 개체의 속성은 개별적으로 할당되며 다른 개체와 값을 공유하지 않습니다. 클래스 내부에서는 @ 연산자를 사용하여 이러한 속성에 액세스하고 클래스 외부에서는 접근자 메서드 라는 공개 메서드를 사용하여 액세스합니다. 아래에서는 위에서 정의한 Box 클래스를 인스턴스로 취하고 @width 및 @height를 Box 클래스의 인스턴스 변수로 사용합니다.

class Box
   def initialize(w,h)
      # 给实例变量赋值
      @width, @height = w, h
   end
end

Accessor & Setter 메소드

클래스 외부에서 변수를 사용하려면 accessor 메소드 내부에서 이러한 변수를 정의해야 합니다. accessor는 실제로 getter와 동일합니다. 다음 예에서는 접근자 메서드의 사용법을 보여줍니다.

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造函数
   def initialize(w,h)
      @width, @height = w, h
   end

   # 访问器方法
   def printWidth
      @width
   end

   def printHeight
      @height
   end
end

# 创建对象
box = Box.new(10, 20)

# 使用访问器方法
x = box.printWidth()
y = box.printHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"


위 코드가 실행되면 다음과 같은 결과가 생성됩니다.

Width of the box is : 10
Height of the box is : 20

변수 값에 액세스하는 데 사용되는 접근자 메서드와 유사하게 Ruby는 다음을 제공합니다. 클래스 외부의 변수 값, 소위 setter 메소드는 다음과 같이 정의됩니다.

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end

   # 访问器方法
   def getWidth
      @width
   end
   def getHeight
      @height
   end

   # 设置器方法
   def setWidth=(value)
      @width = value
   end
   def setHeight=(value)
      @height = value
   end
end

# 创建对象
box = Box.new(10, 20)

# 使用设置器方法
box.setWidth = 30
box.setHeight = 50

# 使用访问器方法
x = box.getWidth()
y = box.getHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"


위 코드를 실행하면 다음과 같은 결과가 생성됩니다.

Width of the box is : 30
Height of the box is : 50

인스턴스 메소드

인스턴스 메소드는 다른 메소드와 마찬가지로 def 키워드를 사용하여 정의되지만, 아래 예와 같이 클래스 인스턴스를 통해서만 사용할 수 있습니다. 해당 기능은 인스턴스 변수에 액세스하는 것에만 국한되지 않고 필요에 따라 다른 많은 작업도 수행할 수 있습니다.

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 创建对象
box = Box.new(10, 20)

# 调用实例方法
a = box.getArea()
puts "Area of the box is : #{a}"


위 코드를 실행하면 다음과 같은 결과가 생성됩니다.

Area of the box is : 200

클래스 메서드 및 클래스 변수

클래스 변수는 클래스의 모든 인스턴스에서 공유되는 변수입니다. 즉, 클래스 변수의 인스턴스는 모든 객체 인스턴스에서 액세스할 수 있습니다. 클래스 변수에는 두 개의 @ 문자(@@) 접두사가 붙으며 다음 예제와 같이 클래스 정의에서 초기화되어야 합니다.

클래스 메서드def self.methodname()을 사용하여 정의됩니다. 클래스 메서드는 끝 구분 기호로 끝납니다. 다음 예와 같이 클래스 이름과 함께 classname.methodname 형식을 사용하여 클래스 메서드를 호출할 수 있습니다.

#!/usr/bin/ruby -w

class Box
   # 初始化类变量
   @@count = 0
   def initialize(w,h)
      # 给实例变量赋值
      @width, @height = w, h

      @@count += 1
   end

   def self.printCount()
      puts "Box count is : #@@count"
   end
end

# 创建两个对象
box1 = Box.new(10, 20)
box2 = Box.new(30, 100)

# 调用类方法来输出盒子计数
Box.printCount()


위 코드를 실행하면 다음과 같은 결과가 생성됩니다.

Box count is : 2

to_s 메서드

you 정의된 모든 클래스에는 객체의 문자열 표현을 반환하는 to_s 인스턴스 메서드가 있습니다. 다음은 너비와 높이 측면에서 Box 개체를 나타내는 간단한 예입니다.

#!/usr/bin/ruby -w

class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 定义 to_s 方法
   def to_s
      "(w:#@width,h:#@height)"  # 对象的字符串格式
   end
end

# 创建对象
box = Box.new(10, 20)

# 自动调用 to_s 方法
puts "String representation of box is : #{box}"


위 코드가 실행되면 다음과 같은 결과가 생성됩니다.

String representation of box is : (w:10,h:20)

Access Control

Ruby는 세 가지 수준의 액세스 제어를 제공합니다. 인스턴스 메소드 보호는 공개, 비공개 또는 보호입니다. Ruby는 인스턴스 및 클래스 변수에 대한 액세스 제어를 적용하지 않습니다.

  • 공개 메서드: 공개 메서드는 모든 객체에서 호출할 수 있습니다. 기본적으로 메소드는 항상 비공개인 초기화 메소드를 제외하고 모두 공개됩니다.

  • Private 메서드: Private 메서드는 클래스 외부에서 액세스하거나 볼 수 없습니다. 클래스 메서드만 전용 멤버에 액세스할 수 있습니다.

  • Protected 메서드: Protected 메서드는 클래스 및 해당 하위 클래스의 개체에서만 호출할 수 있습니다. 또한 클래스와 해당 하위 클래스 내에서만 액세스가 가능합니다.

다음은 세 가지 수정자의 구문을 보여주는 간단한 예입니다.

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end

   # 实例方法默认是 public 的
   def getArea
      getWidth() * getHeight
   end

   # 定义 private 的访问器方法
   def getWidth
      @width
   end
   def getHeight
      @height
   end
   # make them private
   private :getWidth, :getHeight

   # 用于输出面积的实例方法
   def printArea
      @area = getWidth() * getHeight
      puts "Big box area is : #@area"
   end
   # 让实例方法是 protected 的
   protected :printArea
end

# 创建对象
box = Box.new(10, 20)

# 调用实例方法
a = box.getArea()
puts "Area of the box is : #{a}"

# 尝试调用 protected 的实例方法
box.printArea()


위 코드를 실행하면 다음과 같은 결과가 생성됩니다. 여기서 첫 번째 메서드 호출은 성공했지만 두 번째 메서드에서는 문제가 발생합니다.

Area of the box is : 200
test.rb:42: protected method `printArea' called for #
<Box:0xb7f11280 @height=20, @width=10> (NoMethodError)

클래스 상속

상속은 객체지향 프로그래밍에서 가장 중요한 개념 중 하나입니다. 상속을 사용하면 다른 클래스를 기반으로 클래스를 정의할 수 있으므로 애플리케이션을 더 쉽게 만들고 유지 관리할 수 있습니다.

상속은 코드 재사용과 빠른 실행에 도움이 됩니다. 불행히도 Ruby는 다중 상속을 지원하지 않지만 Ruby는 mixins을 지원합니다. 믹스인은 인터페이스 부분만 상속할 수 있는 다중 상속의 특정 구현과 같습니다.

클래스를 생성할 때 프로그래머는 새 클래스가 기존 클래스의 멤버를 상속하도록 직접 지정할 수 있으므로 처음부터 새 데이터 멤버와 멤버 함수를 작성할 필요가 없습니다. 이 기존 클래스를 기본 클래스 또는 상위 클래스라고 하고 새 클래스를 파생 클래스 또는 하위 클래스라고 합니다.

Ruby는 상속이라는 개념도 제공합니다. 다음 예에서는 이 개념을 설명합니다. 클래스 확장 구문은 매우 간단합니다. 클래스 문에 < 문자와 상위 클래스 이름을 추가하기만 하면 됩니다. 예를 들어, BigBox 클래스는 아래에서 Box의 하위 클래스로 정의됩니다.

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 定义子类
class BigBox < Box

   # 添加一个新的实例方法
   def printArea
      @area = @width * @height
      puts "Big box area is : #@area"
   end
end

# 创建对象
box = BigBox.new(10, 20)

# 输出面积
box.printArea()


위 코드가 실행되면 다음과 같은 결과가 생성됩니다.

Big box area is : 200

메소드 오버로딩

새로운 기능이지만 때로는 부모 클래스에 이미 정의된 메서드의 동작을 변경하고 싶을 수도 있습니다. 이때 다음 예와 같이 메소드 이름을 변경하지 않고 메소드의 기능을 오버로드할 수 있습니다.

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 定义子类
class BigBox < Box

   # 改变已有的 getArea 方法
   def getArea
      @area = @width * @height
      puts "Big box area is : #@area"
   end
end

# 创建对象
box = BigBox.new(10, 20)

# 使用重载的方法输出面积
box.getArea()


위 예의 출력 결과는 다음과 같습니다.

Big box area is : 200

Operatoroverloading

희망합니다 + 연산자를 사용하려면 * 연산자를 사용하여 상자의 너비와 높이를 곱하고 단항 연산자 -를 사용하여 상자의 너비와 높이를 부정하는 방식으로 두 Box 개체의 벡터 추가를 수행합니다. 다음은 수학적 연산자 정의가 포함된 Box 클래스 버전입니다.

class Box
  def initialize(w,h) # 初始化 width 和 height
    @width,@height = w, h
  end

  def +(other)         # 定义 + 来执行向量加法
    Box.new(@width + other.width, @height + other.height)
  end

  def -@               # 定义一元运算符 - 来对 width 和 height 求反
    Box.new(-@width, -@height)
  end

  def *(scalar)        # 执行标量乘法
    Box.new(@width*scalar, @height*scalar)
  end
end

객체 고정

때때로 객체가 변경되는 것을 방지하고 싶을 때가 있습니다. Object에서는 효과적으로 객체를 상수로 바꾸는 동결 메서드를 사용하여 이를 수행합니다. Object.freeze를 호출하여 모든 개체를 고정할 수 있습니다. 고정된 개체는 수정할 수 없습니다. 즉, 인스턴스 변수를 변경할 수 없습니다.

Object.frozen? 메소드를 사용하면 특정 객체가 동결되었는지 확인할 수 있습니다. 이 메서드는 객체가 고정된 경우 true를 반환하고, 그렇지 않으면 false 값을 반환합니다. 다음 예에서는 이 개념을 설명합니다.

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end

   # 访问器方法
   def getWidth
      @width
   end
   def getHeight
      @height
   end

   # 设置器方法
   def setWidth=(value)
      @width = value
   end
   def setHeight=(value)
      @height = value
   end
end

# 创建对象
box = Box.new(10, 20)

# 让我们冻结该对象
box.freeze
if( box.frozen? )
   puts "Box object is frozen object"
else
   puts "Box object is normal object"
end

# 现在尝试使用设置器方法
box.setWidth = 30
box.setHeight = 50

# 使用访问器方法
x = box.getWidth()
y = box.getHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"


위 코드를 실행하면 다음과 같은 결과가 생성됩니다.

Box object is frozen object
test.rb:20:in `setWidth=': can't modify frozen object (TypeError)
        from test.rb:39

클래스 상수

직접 숫자 값이나 문자열을 전달하여 클래스 내부에 상수를 정의할 수 있습니다. 정의할 변수에 값을 할당하면 상수 정의에 @ 또는 @@를 사용할 필요가 없습니다. 관례적으로 상수 이름은 대문자로 표시됩니다.

상수가 정의되면 해당 값을 변경할 수 없습니다. 변수에 액세스하는 것처럼 클래스 내부에서 직접 상수에 액세스할 수 있지만, 클래스 외부에서 상수에 액세스하려면 classname ::을 사용해야 합니다. 아래 예와 같이 상수입니다.

#!/usr/bin/ruby -w

# 定义类
class Box
   BOX_COMPANY = "TATA Inc"
   BOXWEIGHT = 10
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 创建对象
box = Box.new(10, 20)

# 调用实例方法
a = box.getArea()
puts "Area of the box is : #{a}"
puts Box::BOX_COMPANY
puts "Box weight is: #{Box::BOXWEIGHT}"


위 코드를 실행하면 다음과 같은 결과가 나옵니다.

Area of the box is : 200
TATA Inc
Box weight is: 10

클래스 상수는 인스턴스 메소드처럼 상속되거나 오버로드될 수 있습니다.

할당을 사용하여 객체 생성

객체 생성자를 호출하지 않고 객체를 생성하려는 상황이 있을 수 있습니다. initialize 즉, 새 메소드를 사용하여 객체를 생성합니다. 이 경우 초기화되지 않은 객체를 생성하기 위해 할당을 호출할 수 있습니다. 다음 예에 나와 있습니다.

#!/usr/bin/ruby -w

# 定义类
class Box
   attr_accessor :width, :height

   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end

   # 实例方法
   def getArea
      @width * @height
   end
end

# 使用 new 创建对象
box1 = Box.new(10, 20)

# 使用 allocate 创建两一个对象
box2 = Box.allocate

# 使用 box1 调用实例方法
a = box1.getArea()
puts "Area of the box is : #{a}"

# 使用 box2 调用实例方法
a = box2.getArea()
puts "Area of the box is : #{a}"


위 코드를 실행하면 다음과 같은 결과가 나옵니다.

Area of the box is : 200
test.rb:14: warning: instance variable @width not initialized
test.rb:14: warning: instance variable @height not initialized
test.rb:14:in `getArea': undefined method `*' 
   for nil:NilClass (NoMethodError) from test.rb:29

클래스 정보

Ruby의 self와 Java의 이것은 유사점도 있지만 매우 다릅니다. Java 메소드는 인스턴스 메소드에서 참조되므로 이는 일반적으로 현재 객체를 가리킵니다. Ruby의 코드는 한 줄씩 실행되므로 self는 상황에 따라 다른 의미를 갖습니다. 다음 인스턴스를 살펴보겠습니다. .

#!/usr/bin/ruby -w

class Box
   # 输出类信息
   puts "Class of self = #{self.class}"
   puts "Name of self = #{self.name}"
end


위 코드가 실행되면 다음과 같은 결과가 생성됩니다.

Class of self = Class
Name of self = Box

이는 클래스를 현재 객체로 만들어 클래스 정의를 실행할 수 있다는 의미입니다. 또한 메소드 정의를 실행하는 동안 메타클래스와 상위 클래스의 메소드를 사용할 수 있음을 의미합니다.