この記事では、OOP(オブジェクト指向プログラミング)の開発の次の段階へのアプローチの1つについて説明します。OOPへの古典的なアプローチは、継承の概念に基づいており、継承は、既製のコードの使用と変更に深刻な制限を課します。新しいクラスを作成するときに、既存のクラスから継承したり(ひし形の継承の問題)、他の多くのクラスがすでに継承している既存のクラスを変更したり(壊れやすい(または過度に肥大化した)基本クラス)できるとは限りません。Delightプログラミング言語を開発する際、クラスとその構成を操作するための代替アプローチであるCPC(コンポーネント指向プログラミング)が選択されました。
ポイントにまっすぐ
言語の基本、その構文、およびCPCの規則から始める必要があります。しかし、これはかなり退屈なので、特定のゲームの例に直接進みましょう。構成自体はOOPと同じ原則に基づいて構築されているため、以下のすべてを理解するには、OOPの完全な知識が必要です。それがどのように機能するかについての詳細は、この後の次のセクションで見つけることができます。
一部のクリーチャーがマップ内を移動できる条件付きゲームの例を考えてみましょう。これらの生き物の行動のコードを書いてみましょう。基本クラスから始めましょう。
class BaseBehavior
unitPos: UnitPos [shared]
fn DoTurn [virtual]
class PathBuilder
unitPos: UnitPos [shared]
fn Moving:boolean [virtual]
...
fn BuildPath(x:int, y:int) [virtual]
...
// ... and some more helper functions ...
BaseBehavior-クリーチャーの基本的な動作を担当します。クラス自体にはロジックがなく、必要な宣言のみがあります。
PathBuilderは、地面に沿ったパスを見つける役割を担うクラスです(障害物の回避を含む)。
[shared]修飾子は、このフィールドが最終クラスのすべてのサブクラスによって共有されることを意味します。
, :
class SimpleBehavior
base: BaseBehavior [shared]
path: PathBuilder [shared]
fne DoTurn // override of BaseBehavior.DoTurn
if path.Moving = false
path.BuildRandomPath
class AgressiveBehavior
open SimpleBehavior [shared]
fne DoTurn // override of SimpleBehavior.DoTurn
d: float = path.GetDistance(player.x, player.y) // get distance from this unit to player
if d < 30
path.BuildPath(player.x, player.y) // run to player
else
nextFn // inherited call to next DoTurn
class ScaredBehavior
open SimpleBehavior [shared]
fne DoTurn // override of SimpleBehavior.DoTurn
d: float = path.GetDistance(player.x, player.y) // get distance from this unit to player
if d < 50
path.BuildPathAwayFrom(player.x, player.y) // run away from player
else
nextFn // inherited call to next DoTurn
:
SimpleBehavior - .
AgressiveBehavior - , . SimpleBehavior.
ScaredBehavior - , SimpleBehavior.
open - .
fne - (override) .
nextFn - .
, :
class UncertainBehavior
open AgressiveBehavior [shared]
open ScaredBehavior [shared]
"" . , DoTurn, AgressiveBehavior.DoTurn. , . , ScaredBehavior.DoTurn - , . , SimpleBehavior.DoTurn .
(AgressiveBehavior), (ScaredBehavior) (UncertainBehavior). ? ? ? . . :
class PathBuilder_air //
path: PathBuilder [shared]
fne BuildPath(x:int, y:int)
...
class PathBuilder_water //
path: PathBuilder [shared]
fne BuildPath(x:int, y:int)
...
:
class Shark
open PathBuilder_water [shared]
open AgressiveBehavior [shared]
"", , AgressiveBehavior, , PathBuilder (shared), AgressiveBehavior ( SimpleBehavior) PathBuilder_water ( PathBuilder). AgressiveBehavior , . , - , :
class Fish
open PathBuilder_water [shared]
open ScaredBehavior [shared]
class Eagle
open PathBuilder_air [shared]
open UncertainBehavior [shared]
class Pigeon
open PathBuilder_air [shared]
open ScaredBehavior [shared]
class Wolf
open AgressiveBehavior [shared]
, - - -.
Delight
Delight :
class NonVirtualClass
val: OtherClass
fn SomeFn
Trace('Hello world')
val , OtherClass.
, , [virtual]
fn SomeFn [virtual]
Trace('Hello virtual world')
/ fne ( fn)
fne SomeFn
Trace('Hello overrided world')
( ) . , , [shared] (), fne :
class BaseClass
fn SomeFn [virtual]
Trace('Hello virtual world')
class NewClass
base: BaseClass [shared]
fne SomeFn
Trace('Hello overrided world')
nextFn
nextFn .
( ) ++
class BaseClass
{
public:
virtual void SomeFn()
{
Trace('Hello virtual world');
}
};
class NewClass : public virtual BaseClass
{
virtual void SomeFn() override
{
Trace('Hello overrided world');
BaseClass::SomeFn();
}
};
[shared], . , shared , , [shared] , , [shared] ( vtable).
:
class Base
val: int
class ClsA
base: Base [shared]
class ClsB
base: Base [shared]
class ClsC
a: ClsA [shared]
b: ClsB [shared]
ClsC, (Base, ClsA, ClsB) val () . , ++.
, ( , , ), . Delight open ( ). , ( this).
class ClsA
open Base [shared]
fne Constructor
val = 10
, . , :
, (shared) , ;
(shared) , .
, :
, ;
.
, nextFn. , (virtual call), (inherited call).
, :
class Base
fn SomeVirtFn [virtual]
Trace('Base')
class ClsA
open Base [shared]
fne SomeVirtFn
Trace('ClsA')
class ClsB
open Base [shared]
fne SomeVirtFn
Trace('ClsB')
class ClsC
open ClsA [shared]
open ClsB [shared]
fne SomeVirtFn
Trace('ClsC')
....
fn Main
c: ClsC
c.SomeVirtFn
:
ClsC
ClsA
ClsB
Base
このアプローチにより、階層の同じレベルにありながら、あるクラスの関数を別のクラスでオーバーロードできます。このおかげで、クラスは他の人の機能と重複または補完する既製のコンポーネントで構成でき、コードの構成が大幅に容易になります。構成中に、最終クラスの主な機能はいくつかの基本的な構成要素に分解され、それらの組み合わせによって望ましい結果が得られます。Delightは静的コード構成もサポートしていますが、これはすでに別の記事の資料です。