1. ホーム
  2. スクリプト・コラム
  3. ルア

Luaのオブジェクト指向機能の紹介

2022-02-10 01:46:54

 オブジェクト指向の機能

  •     クラス。クラスは、状態(メンバ変数)の初期値や動作の実装を提供するオブジェクトを作成するために使用される拡張可能なテンプレートです。
  •     オブジェクト。クラスのインスタンスであり、それとは別にメモリが割り当てられている。
  •     インヘリタンス。あるクラスの変数や関数が他のクラスに継承される概念です。
  •     カプセル化。データと関数を組み合わせたクラス内のメソッドのことです。データは関数の助けを借りてクラスの外からアクセスすることができる。データの抽象化とも呼ばれる。

LuaのOOP

LuaのテーブルとLuaの第一級関数でオブジェクト指向を実装する。オブジェクトは、関数と関連するデータをテーブルに挿入することで形成されます。メタテーブルの助けを借りて継承を実装することができます。メタテーブルは、存在しない関数(メソッド)や親オブジェクトのフィールドを検索する機構を提供します。

Luaのテーブルには、このようなステートオブジェクトと、値に依存しないプロパティであるアイデンティティオブジェクトがあります。同じ値を持つ2つのオブジェクト(テーブル)でも、オブジェクトは異なる値で持つことができますが、それは常に同じオブジェクトである。それは、オブジェクトテーブルのライフサイクルを持つようなもので、独立して作成または作成されます。
実際の例

オブジェクト指向の概念は幅広いですが、理解して最大限に活用することが重要です。

簡単な数学の例で考えてみましょう。私たちはしばしば、円、長方形、正方形といったさまざまな形の中で作業をする場面に遭遇します。

図形は共通のプロパティ領域を持つことができます。したがって、共通のプロパティ領域を持つベースオブジェクトのシェイプから、他のシェイプを拡張することができるのです。各図形は、長方形が長さ、幅、面積などのプロパティを持ち、関数としてprintAreaやcalcAreaを持つように、独自のプロパティと関数を持つことができます。
簡単なクラスを作成する

簡単なクラスは、以下のような3つのプロパティarea, length, widthを持つ矩形を実装しています。また、計算された面積を表示するための関数printAreaを持っています。

コピーコード コードは以下の通りです。
-- Meta class
Rectangle = {area = 0, length = 0, breadth = 0}

-- Derived class method new
function Rectangle:new (o,length,breadth)
  o = o or {}
  setmetatable(o, self)
  self.__index = self
  self.length = length or 0
  self.breadth = breadth or 0
  self.area = length*breadth;
  return o
end

-- Derived class method printArea
function Rectangle:printArea ()
  print("The area of Rectangle is ",self.area)
end

オブジェクトの作成

オブジェクトの作成は、クラスのインスタンスにメモリーを割り当てる作業です。各オブジェクトは独自のメモリーを持ち、共通のクラスデータを共有します。

コピーコード コードは以下の通りです。
r = Rectangle:new(nil,10,20)

アクセスプロパティ

クラス内のプロパティにアクセスするには、以下のようにドット.演算子を使って属性にアクセスします。

コピーコード コードは以下の通りです。
print(r.length)

メンバ関数へのアクセス

オブジェクトのメンバー関数にアクセスするには、以下のようにコロン演算子を使用します。

コピーコード コードは以下の通りです。
r:printArea()

メモリが確保され、初期値が設定される。初期化処理は、他のオブジェクト指向言語よりも構築することができる。上図のように、単純に値を設定する関数である。
完全な例

それでは、オブジェクト指向のLuaを使った完全な例を見てみましょう。

コピーコード コードは以下の通りです。
-- Meta class
Shape = {area = 0}

-- Base class method new
function Shape:new (o,side)
  o = o or {}
  setmetatable(o, self)
  self.__index = self
  side = side or 0
  self.area = side*side;
  return o
end

-- Base class method printArea
function Shape:printArea ()
  print("The area is ",self.area)
end

-- Creating an object
myshape = Shape:new(nil,10)

myshape:printArea()

上記のプログラムを実行すると、次のような出力が得られます。

コピーコード コードは以下の通りです。
The area is 100

Luaにおける継承

継承とは、形状を単純に長方形、正方形などに拡張した基本オブジェクトの扱いである。実世界で基本的な性質や機能を共有し、拡張するためによく使われる。

簡単なクラスの拡張を見てみましょう。以下のようなクラスがあります。

コピーコード コードは以下の通りです。
-- Meta class
Shape = {area = 0}
-- Base class method new
function Shape:new (o,side)
  o = o or {}
  setmetatable(o, self)
  self.__index = self
  side = side or 0
  self.area = side*side;
  return o
end
-- Base class method printArea
function Shape:printArea ()
  print("The area is ",self.area)
end

正方形クラスに拡張できる形状は以下の通りです。

コピーコード コードは以下の通りです。
Square = Shape:new()
-- Derived class method new
function Square:new (o,side)
  o = o or Shape:new(o,side)
  setmetatable(o, self)
  self.__index = self
  return o
end

基本関数のオーバーロード

以下のように、ベースクラスの関数をオーバーロードすることで、クラスを派生させる代わりにベースクラスの関数を使用し、それ自体を実装することができます。

コピーコード コードは以下の通りです。
-- Derived class method printArea
function Square:printArea ()
  print("The area of square is ",self.area)
end

継承の完全な例

Luaで拡張できる簡単なクラスの実装は、上記のように別の新しいメソッドをメタ化しています。ベースクラスのすべてのメンバ変数と関数は、派生クラスで保持されます。

コピーコード コードは以下の通りです。
 -- Meta class
Shape = {area = 0}
-- Base class method new
function Shape:new (o,side)
  o = o or {}
  setmetatable(o, self)
  self.__index = self
  side = side or 0
  self.area = side*side;
  return o
end
-- Base class method printArea
function Shape:printArea ()
  print("The area is ",self.area)
end

-- Creating an object
myshape = Shape:new(nil,10)
myshape:printArea()

Square = Shape:new()
-- Derived class method new
function Square:new (o,side)
  o = o or Shape:new(o,side)
  setmetatable(o, self)
  self.__index = self
  return o
end

-- Derived class method printArea
function Square:printArea ()
  print("The area of square is ",self.area)
end

-- Creating an object
mysquare = Square:new(nil,10)
mysquare:printArea()

Rectangle = Shape:new()
-- Derived class method new
function Rectangle:new (o,length,breadth)
  o = o or Shape:new(o)
  setmetatable(o, self)
  self.__index = self
  self.area = length * breadth
  return o
end

-- Derived class method printArea
function Rectangle:printArea ()
  print("The area of Rectangle is ",self.area)
end

-- Creating an object
myrectangle = Rectangle:new(nil,10,20)
myrectangle:printArea()

上記のプログラムを実行すると、次のような出力が得られます。

コピーコード コードは以下の通りです。
The area is 100
The area of square is 100
The area of Rectangle is 200

上記の例では、基底クラスSquareから2つの派生クラスRectangleとSquareを作成しました。したがって、派生クラスは、ここで基底クラスの機能を変更することができます。この実装例では、派生クラスが関数printAreaを置き換えることになります。