Rozdělení velkých tříd ve Scale

I když je Scala velice stručný jazyk, může se stát, že jedna třída přesáhne rozumnou velikost a bylo by nejlepší, kdyby byla rozdělena do souborů. Ale jak toho dosáhnout, když třída (na rozdíl od jmenného prostoru) musí být v jenom souboru?
C# 2.0 pro podobné případy zavedl partial class, vlastnost hlavně určenou pro částečně generované třídy – v jednom souboru automaticky vygenerovaná část třídy (třeba výsledek GUI builderu), ve druhém vlastní kód.
// file1.cs: public partial class MyClass // klíčové slovo partial se postará o všechnu magii { public void MyMethod1() { /* Manually written code */ } }
// file2.cs: public partial class MyClass { public void MyMethod2() { /* Automatically generated code */ } }
Scala je zatraceně flexibilní a stejného výsledku se dá dosáhnout bez rozšíření jazyka.
Pochopitelně se pro tento účel dá zneužít dědičnost: jedna část kódu (třeba ta automaticky vygenerovaná) přijde do abstraktního rodiče, další do potomka. Tenhle přístup funguje, ale jednak zneužíváme dědičnost pro něco, k čemu není určena a druhak je velice neflexibilní. Potomek může přistupovat k členům rodiče, ale ne naopak a přesně to potřebujeme. Tohle je principiální omezení dědičnosti a nemůžeme s ním nic dělat. Ale nám nejde o dědičnost, nám jde o rozdělení jedné velké třídy do několika souborů. Dědičnost je zkrátka špatný nástroj.
Mnohem flexibilnější je použití traitů a self-typů. Můžeme se odkazovat na členy ve všech ostatních částech a zároveň můžeme rozdělit třídu do libovolného počtu částí.
// hlavní třída, do které se mixnou všechny ostatní části class MyClass extends MyClassMixin with MyClassMixin2 { val myProperty = "Anomalocaris Detrimentum" } trait MyClassMixin { this: MyClass => // můžu přistupovat ke všem členům třídy MyClass a všem mixnutých traitů, // protože self-typ zajišťuje, že tento trait bude přimíchán do třídy MyClass // nebo nějakého jeho potomka def myMethod = myProperty } trait MyClassMixin2 { this: MyClass => def myMethod2 = 2084 } // test // val c = new MyClass c.myProperty // definováno v MyClass c.myMethod // definováno v MyClassMixin c.myMethod2 // definováno v MyClassMixin2
Tohhle přístup je založen na návrhovém vzoru cake pattern, který se byl poprvé uveřejněn v článku Scalable Component Abstractions. Cake pattern je ale mnohem mocnější, umožňuje rozdělit systém na samostatné komponenty, které mezi sebou mají závislosti a provozovat plnohodnotný dependency injection bez použití externích nástrojů.