Artikel ini membahas salah satu pendekatan untuk tahap selanjutnya pengembangan OOP (pemrograman berorientasi objek). Pendekatan klasik untuk OOP didasarkan pada konsep pewarisan, yang pada gilirannya memberlakukan pembatasan serius pada penggunaan dan modifikasi kode yang sudah jadi. Saat membuat kelas baru, tidak selalu mungkin untuk mewarisi dari kelas yang sudah ada (masalah warisan berbentuk berlian ) atau memodifikasi kelas yang sudah ada yang sudah diwarisi oleh banyak kelas lain (kelas dasar yang rapuh (atau terlalu membengkak)). Saat mengembangkan bahasa pemrograman Delight, pendekatan alternatif dipilih untuk bekerja dengan kelas dan komposisinya - BPK (pemrograman berorientasi komponen).
Langsung ke intinya
Kita harus mulai dengan dasar-dasar bahasa, sintaksisnya, dan aturan BPK. Tapi ini cukup membosankan, jadi mari kita langsung ke contoh game tertentu. Untuk memahami semua hal berikut, diperlukan pengetahuan penuh tentang OOP, karena komposisinya sendiri dibangun di atas prinsip yang sama dengan OOP. Rincian lebih lanjut tentang cara kerjanya dapat ditemukan di bagian selanjutnya setelah ini.
Mari kita pertimbangkan contoh dari permainan bersyarat di mana beberapa makhluk dapat bergerak di sekitar peta. Mari kita tulis kode untuk perilaku makhluk-makhluk ini. Mari kita mulai dengan kelas dasar.
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 - bertanggung jawab atas perilaku dasar makhluk, kelas itu sendiri tidak memiliki logika, hanya deklarasi yang diperlukan.
PathBuilder adalah kelas yang bertanggung jawab untuk menemukan jalur di sepanjang tanah (termasuk menghindari rintangan).
Pengubah [bersama] berarti bahwa bidang ini akan dibagikan oleh semua subkelas dari kelas akhir.
, :
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
Pendekatan ini memungkinkan Anda untuk membebani fungsi dari satu kelas dengan kelas lainnya, sambil berada pada tingkat hierarki yang sama. Berkat ini, kelas dapat terdiri dari komponen siap pakai yang tumpang tindih atau melengkapi fungsi orang lain, yang sangat memudahkan komposisi kode. Selama komposisi, fungsionalitas utama dari kelas akhir dipecah menjadi beberapa blok bangunan dasar, yang kombinasinya memberikan hasil yang diinginkan. Delight juga mendukung komposisi kode statis, tetapi ini sudah menjadi bahan untuk artikel lain.