Komposition statt Vererbung in der Programmiersprache Delight

Dieser Artikel beschreibt einen der Ansätze für die nächste Entwicklungsstufe von OOP (objektorientierte Programmierung). Der klassische Ansatz für OOP basiert auf dem Konzept der Vererbung, das wiederum die Verwendung und Änderung von vorgefertigtem Code stark einschränkt. Beim Erstellen neuer Klassen ist es nicht immer möglich, von vorhandenen Klassen zu erben (das Problem der rautenförmigen Vererbung) oder vorhandene Klassen zu ändern, von denen viele andere Klassen bereits geerbt haben (eine fragile (oder übermäßig aufgeblähte) Basisklasse). Bei der Entwicklung der Programmiersprache Delight wurde ein alternativer Ansatz für die Arbeit mit Klassen und deren Zusammensetzung gewählt - CPC (Component-Oriented Programming).





Auf den Punkt

, . , . , , . , - , .





, . . .





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
      
      



Mit diesem Ansatz können Sie Funktionen einer Klasse mit einer anderen überladen, während Sie sich auf derselben Hierarchieebene befinden. Dank dessen können Klassen aus vorgefertigten Komponenten bestehen, die die Funktionen anderer Personen überlappen oder ergänzen, was die Komposition des Codes erheblich erleichtert. Während der Komposition wird die Hauptfunktionalität der Abschlussklasse in mehrere Grundbausteine ​​unterteilt, deren Kombination die gewünschten Ergebnisse liefert. Delight unterstützt auch die statische Code-Komposition, dies ist jedoch bereits Material für einen anderen Artikel.








All Articles