[ Impressum ]

Die Klassenhierarchie von Zebra

www.Rozek.de > Zebra > Investigation > ClassHierarchy
Die von Zebra [1] bereitgestellte und verwendete Variante der Objekt-Orientierung [2][3] verlangt bei der Modifikation einer Klasse zugleich auch die Anpassung aller bereits davon abgeleiteten Unterklassen.

Da es keine direkte Möglichkeit gibt, alle Unterklassen einer gegebenen Klasse zu ermitteln, muss für eine solche Anpassung zunächst eine Klassenhierarchie erstellt und bei Bedarf durchlaufen werden.

Zebra-Klassenhierarchie

Das nachstehend beschriebene Verfahren erstellt zunächst eine Liste aller Klassen in allen Zebra-Paketen und bringt diese dann mithilfe der Klassen-Variable $parent (die bekanntlich Klassen von Schnittstellen unterscheidet) zueinander in Beziehung. Das Ergebnis ist ein Objekt mit den Namen aller Klassen ohne Oberklasse, hinter denen (rekursiv) weitere Objekte mit den Namen aller davon abgeleiteten Klassen stehen:
zebra.ClassHierarchy = function ClassHierarchy () {
var ClassSet = {}; // collect all classes in all zebra packages
zebra(function (PackageName, Package) {
for (var ClassName in Package) {
if (Package.hasOwnProperty(ClassName)) {
var Class = Package[ClassName];
if (
(typeof(Class) === 'function') &&
(typeof(Class._hash_) === 'string') &&
(Class._hash_.slice(0,7) === '$zebra_')
) {
if ('$parent' in Class) { // ignore any interfaces
ClassSet[PackageName + '.' + ClassName] = Class;
};
};
};
};
});


/**** auxiliary functions: split full class name into its parts ****/


var PackageNameOf = function PackageNameOf (fullClassName) {
return fullClassName.replace(/[.][^.]+$/,'');
};


var ClassNameOf = function ClassNameOf (fullClassName) {
return fullClassName.replace(/^.*[.]/,'');
};


/**** determine the subclass of any Zebra class ****/


var SubclassSet = {};
for (var fullClassName in ClassSet) {
SubclassSet[fullClassName] = []; // initialize all entries
};


for (var fullClassName in ClassSet) {
var Class = zebra( // fetch package
PackageNameOf(fullClassName)
) [ClassNameOf(fullClassName)]; // fetch class in package


var SuperClass = Class.$parent;
if (SuperClass !== null) { // class has no superclass
for (var SuperClassName in ClassSet) { // find superclass in set
if (ClassSet[SuperClassName] === SuperClass) {
SuperClass = SuperClassName; // not the best style, I know...
break;
};
};


if (typeof(SuperClass) === 'string') { // means: name was found
SubclassSet[SuperClass].push(fullClassName);
} else {
if (fullClassName === 'ui.Window') { // weird exception...
SubclassSet['ui.Panel'].push('ui.Window');
} else {
throw new Error(
'could not find superclass of "' + fullClassName + '"'
);
};
};
};
};


/**** auxiliary function: get the subclass hierarchy of a given class ****/


var SubclassHierarchy = function SubclassHierarchy (fullClassName) {
var ClassHierarchy = {};
var SubclassList = SubclassSet[fullClassName];
for (var i = 0; i < SubclassList.length; i++) {
var fullSubclassName = SubclassList[i];
ClassHierarchy[fullSubclassName] = SubclassHierarchy(fullSubclassName);
};
return ClassHierarchy;
};


/**** now actually build the class hierarchy ****/


var ClassHierarchy = {};
for (var fullClassName in ClassSet) {
var Class = zebra( // fetch package
PackageNameOf(fullClassName)
) [ClassNameOf(fullClassName)]; // fetch class in package


var SuperClass = Class.$parent;
if (SuperClass === null) { // class has no superclass
ClassHierarchy[fullClassName] = SubclassHierarchy(fullClassName);
};
};


/**** that's it! ****/


return ClassHierarchy;
};

Eine kleine Hilfsmethode ermöglicht eine strukturierte Ausgabe dieses verschachtelten Objektes:
/**** auxiliary function: display given class hierarchy ****/


var showHierarchy = function (ClassHierarchy, Prefix) {
var ClassNameList = [];
for (var fullClassName in ClassHierarchy) {
if (ClassHierarchy.hasOwnProperty(fullClassName)) {
ClassNameList.push(fullClassName);
};
};
ClassNameList.sort();
for (var i = 0; i < ClassNameList.length; i++) {
var fullClassName = ClassNameList[i];


sayln(Prefix + ' - ' + fullClassName);
showHierarchy(ClassHierarchy[fullClassName], Prefix + ' ');
};
};

Das folgende kleine JSFiddle zeigt die derzeitige Klassenhierarchie:



Da Schnittstellen nicht von anderen Klassen oder Schnittstellen abgeleitet werden können, tauchen sie in der Hierarchie nicht auf.

Den Quelltext der Funktion zebra.ClassHierarchy können Sie sich hier herunterladen - die Funktion ist aber auch Bestandteil meines kompletten "ZebraTweaks"-Paketes.

Literaturhinweise

[1]
Andrei Vishneuski
HTML5 Rich UI JavaScript Library
Zebra ist eine noch relativ neue JavaScript-Bibliothek für grafische Benutzeroberflächen in Web-Anwendungen. Diese Seite ist der primäre Anlaufpunkt, wenn Sie sich für Zebra interessieren.
[2]
Andrei Vishneuski
Easy OOP
Zebra implementiert seine eigene, an Java angelehnte, Variante der Objekt-Orientierung. Diese Seite gibt einen kurzen Überblick über die Konzepte.
[3]
Andrei Vishneuski
Easy OOP
Zebra implementiert seine eigene, an Java angelehnte, Variante der Objekt-Orientierung. Diese Seite erläutert die zugrunde liegenden Konzepte.