Home

News

Software

Bilder

Texte
  - Börse
  - Favoriten
    - Goddesses
  - Winsock
  - Diplomarbeit
    - Titel
    - Inhalt
    - Einleitung
    - Kapitel 2
      - Kapitel 2-1
      - Kapitel 2-2
      - Kapitel 2-3
    - Kapitel 3
      - Kapitel 3-1
      - Kapitel 3-2
      - Kapitel 3-3
    - Ausblick
    - Literatur
    - Anhang

Alles fliesst

Comics

Musik

Leben

Links

Sitemap

Admin


Erotisches bei
AsianThumbs.org

[ TEXT-INDEX] [ 25-stunden-woche] [ Abteilungsbildung] [ Aggression] [ Alleine-im-all] [ Arbeit-im-wertewandel] [ Arbeitsgestaltung] [ Arbeitszufriedenheit] [ Atlantis] [ Betriebssysteme-fakten] [ Betriebssysteme-fragen] [ Betriebssysteme] [ Casetools] [ Client-server-computing] [ Computerknowhow] [ Das-werkzeug-der-mathematik] [ Datenmodellierung] [ Der-gang-ins-all] [ Der-gekruemmte-raum] [ Dialog-arbeitszufriedenheit] [ Eingliederungs-programme] [ Entscheidungstheorie] [ Evolutionaeres-management] [ Familiaer-fraktales-organisationsmodell-1] [ Familiaer-fraktales-organisationsmodell-2] [ Frauenangst] [ Fuehrung] [ Fuzzy-logic-neuronale-netzwerke] [ Ibm-as400] [ Information-retrieval-systeme] [ Informations-management] [ Informations-technik-1] [ Informations-technik-2] [ Ki-mix] [ Leanmanagement] [ Literarischer-stil] [ Mobbing-als-spiel] [ Moderne-arbeitsformen] [ Mythos-ibm] [ Neuronale-netzwerke-mix] [ Objektorientierte-analyse] [ Objektorientierte-entwicklung-cpp] [ Objektorientierte-entwicklung-mix-1] [ Objektorientierte-entwicklung-mix-2] [ Objektorientierte-metriken] [ Objektorientiertes-design] [ Online-transaction-processing] [ Organisationsanalyse] [ Organisationsentwicklung] [ Organisationskultur] [ Organisationspsychologie1] [ Organisationspsychologie2] [ Organisationsstrukturen] [ Organisationstheorie1] [ Organisationstheorie2] [ Organisatorische-effizienz] [ Organisatorische-fuehrung] [ Outsourcing] [ Papierkorbmodell] [ Pc-host-kommunikation] [ Personalbeurteilung] [ Perspektive-in-der-geschichte] [ Philosophie-der-neuzeit] [ Philosophie-des-mittelalters] [ Property-rights-theorie] [ Rationalisierung-in-der-verwaltung] [ Rechnernetze-fragen] [ Rechnernetze-muendlich] [ Rechnernetze] [ Restrukturierung] [ Revitalisierung] [ Simulation-neuronaler-netzwerke] [ Sw-hw-migration] [ Sw-reuse] [ Transzendenz-kunst-religion] [ Und-ward-nicht-mehr-gesehen] [ Verteilte-betriebssysteme] [ Wissensbasierte-systeme] [ Wissenschaftstheorie] [ Wut-und-ihr-nutzen]


Objektorientierte Entwicklung (OOE): Splitter II

von Daniel Schwamm (05.08.1994 bis 09.08.1994)

Aus "Heimat des Dilettantismus"
http://www.henrys.de/daniel/index.php?cmd=texte_objektorientierte-entwicklung-mix-2.htm
nach Schader, Rumbaugh (1994)

Inhalt

1. Model View Controler

2. Parametisierte Funktionen/Klassen

3. Fehler-Handling

4. Sonstiges

1. Model View Controler

Der Model View Controler von Rumbaugh ist eine objektorientierte Framework, die ähnlich wie das Seeheim-Modell vorsieht, das User Interface getrennt von der eigentlichen Applikation zu modellieren. Schematisch baut sich der Model View Controller folgendermaßen auf:

				User

				Controller

View1		View2		View3		View4		View5

			Model (Subjekt, Problemdomäne)

Auf ein Beispiel bezogen sieht obiges Schema folgendermaßen aus:

				
				User

				Steuerung

	Mausklick		Tastatur		Joystick

Cockpit		Sound		Landkarten		Widgets

				Flugsimulator

Flugzeug			Ort			Atmosphäre

2. Parametisierte Funktionen/Klassen

(1) Parametisierte Funktionen: Nachfolgende Funktion erlaubt es, beliebige Objekte auszugeben. Dazu muß nur eine Funktions-Definition mit dem Schlüsselwort "template" angegeben werden, weil der Compiler dann an den Funktionsaufrufen (im main()-Teil) erkennt, für welche Typen er eine eigene Funktionsinstanz implementieren muß.

template <class T> 
void f(T &t) {
	cout << t << endl;
};

struct X {
	char *txtp;
	friend ostream* operator<<(ostream &os, X &x) {
		os << x.txtp;
		return os;
	};
	X(char *tp) { txtp=tp; };
};

void main() {
	int i=100;
	double d=1.2;
	char str[]="Hallo";
	X x("Hurz");
	
	f(i);
	f(d);
	f(str);
	f(x);
};

Folgende Punkte sind bei Funktions-Templates zu beachten:

template <class T> 
T f(T x, T y) {...};

void main() {
	int i=f(10, 1.2);	// ERROR, weil 1.2 kein int!
};

unline template <class T> 	// ERROR: unline/extern/static
void f(T x) {...};		// müssen hinter template <> stehen

template <class T, class S>
void f(T &t) {...};		// ERROR, weil S kein Argument!

(2) Klassen-Templates: Über normale Klassen kann man nur Objekte des gleichen Typs erzeugen. Mit Hilfe der nachfolgenden drei Methoden kann man sich Klassen-Instanzen für jeden beliebigen Typ erzeugen:

* Um z.B. einen Stack zu erzeugen, der Objekte beliebigen Typs verwalten kann, eignet sich der void-Pointer. Statt direkt die Objekte zu verwalten, werden auf dem Stack nur void-Pointer abgelegt, die auf beliebige Objekte zeigen können. Problematisch an solch einem "generischen" Stack ist allerdings, daß auf ein und demselben Stack Objekte verschiedenen Typs verwaltet werden können, was bzgl. Iteratoren u.ä. zu Inkonsistenzen führen könnte.

Beispiel Void_StackC:

class Void_StackC {
public:
	void **Buffer;	
	int Size;	
	int Pos;
	Void_StackC(const int &i=3) {
		Size=i;
		Pos=0;
		if(!(Buffer=new void*[Size])) {
			cout << "*** Not enought memory! ***" << endl;
			exit(0);
		};
	};
	~Void_StackC() { delete [Size] Buffer; };
	void Push(void *vp) { 
		if(!Full()) 
			Buffer[Pos++]=vp; 
	};
	void *Pop() {
		if(!Empty())
			return Buffer[--Pos];
		return NULL;
	};
	int Empty() {return (Pos<=0)?1:0;};
	int Full() {return (Pos>=Size)?1:0;};
};

void main() {
	Void_StackC vi(3);		// offen für alle Arten Pointer
	for(int i=0; i<3; i++)
		vi.Push(new int(i));	// Ablage von int-Pointern
	while(!vi.Empty())
		cout << *((int*) vi.Pop()) << endl;
};

Beispiel Void_QueueC: Der "Trick" bei Queues ist, immer ein Element mehr zu erlauben, als der Anwender wünscht, weil dann durch Pos==Front zu erkennen ist, daß die Schlange leer ist und nicht voll.

class Void_QueueC {
public:
	void **Buffer;	
	int Size;	
	int Pos; 
	int Front;
	Void_QueueC(int &i=10) {
		Size=i+1;
		Pos=Front=0;
		if(!(Buffer=new void*[Size])) {
			cout << "*** Not enought memory! ***" << endl;
			exit(0);
		};
	};
	~Void_QueueC() { delete [Size] Buffer; };
	void Push(void *vp) {
		if(!Full()) {
			Buffer[Pos]=vp;
			Pos=(Pos+1)%Size;
		};
	};
	void *Pop() {
		void *vp;
		if(!Empty()) {
			vp=Buffer[Front];
			Front=(Front+1)%Size;
			return vp;
		};
		return NULL;
	};
	int Empty() {	return (Pos==Front)?1:0; };
	int Full()  {	return (Pos-Front==Size-1 || Front-Pos==1)?1:0; };
};

void main() {
	int i;
	Void_QueueC v(5);		// offen für alle Arten Pointer
	cout << "Queuefront (0 bis 4): "; 
	cin >> v.Front;
	v.Pos=v.Front;
	while(!v.Full()) {
		cout << "Integer: "; 
		cin >> i;
		v.Push(new int(i));		// Ablage von int-Pointern
	};
	while(!v.Empty())
		cout << *((int*)v.Pop()) << endl;
};

* Ein Stack, der verschiedene Objekttypen verwalten kann, läßt sich auch durch Ableitung realisieren. Wir entwickeln die abstrakte Basisklasse "Stack" mit pure-virtual Methoden, von dem dann die benötigten Stacks, z.B. "IntStack", abgeleitet werden können. Diese Methode verlangt einiges an Arbeitsaufwand für den Programmierer, muß er doch für jeden neuen Typ eine eigene Stack-Klasse entwicklen.

* Der effektivste Weg, eine generische Stack-Klasse zu implementieren, stellt die Benutzung von Template-Klassen dar. Bei dieser Methode überlassen wir es dem Compiler, je nach Anforderung die nötigen typspezifischen Stack-Klassen-Instanzen zu erzeugen.

template <class T>
class X {
	int *ip;
	void f(T &t) { cout << t << endl; };
	T g(T &t);
	X() { ip=NULL; };
	X(X<T>&);
};

template <class T> T X<T>::g(T &t) { return ++t; };
template <class T> X<T>::X(X<T> &x) { ip=x.ip; return *this; };

template <class T> void ff(X<T> &x, T &t) { x.f(t); };

void main() {
	X<int> x, y(x);
	X<double> z;
	x.f(7);
	cout << y.g(7) << endl;	
	ff(z, 1.4);
};

Eine von X abgleitete Klasse, die selbst nicht parametisiert ist, muß den Basisklassen-Typ angeben, und hätte dadurch folgendes Aussehen:

class Y:puplic X<int> {...};

Die Elementfunktionen von parametisierten Klassen sind immer parametisierte Funktionen, weil der implizite this-Zeiger parametisiert ist. Für friend-Funktionen dagegen trifft dies nicht zu; hier sind drei Fälle denkbar:

* Die friend-Funktion ist nicht parametisiert. Daraus folgt, daß jede Klassen-Instanz für jeden Typ die gleiche friend-Funktion verwendet.

* Die friend-Funktion enthält parametisierte Argumente. Daraus folgt, daß pro aufgerufenem Typ eine eigene friend-Funktion vom Compiler erzeugt wird.

template <class T>
class X {
	T tt;
	friend void f(X<T>&);
public:
	X(T &t) { tt=t; };
};

template <class T> void f(X<T> &x) { cout << x.tt << endl; };

void main() {
	X<char> x('a');
	f(x);
};

* Ein friend-Funktion enthält zwar parametisierte Argumente, diese stammen jedoch von einer anderen Klasse. Dies bewirkt das gleiche wie der erste Fall.

Achtung: Folgende Dinge sind bei Klassentemplates zu beachten:

* Eingebettete Klassen können nicht parametisiert werden, da Templates immer global zu deklarieren sind.

* Es gilt:

template <class T, int i>
class X {...};

void main() {
	X<int, 10> a;
	X<int, 2*5> b;
	X<int, 11> c;

	b=a;		// OK, weil a und b gleichen Typ X<int, 10> haben!
	a=c;		// ERROR, weil c den Typ X<int, 11> hat!
};

3. Fehler-Handling

In C bzw. C++ wurden Fehler üblicherweise folgendermaßen abgefangen:

int* reserviere(int i) {
	if(i>100) {
		cout << "Index zu groß" << endl;
		exit(1);
	};
	int *ip=new int[i];
	if(ip==NULL) {
		cout << "Kein Speicherplatz mehr" << endl;
		exit(1);
	};
	return ip;
};

void main() {
	int *ip=reserviere(10);
};

Seit einiger Zeit können Fehler auch folgendermaßen behandelt werden (dies erlaubt ein effektiveres Abfangen von Ausnahmen):

struct Ausnahme {
	char *txtp;		// für Fehlertext
	Ausnahme(const char *tp) { txtp=tp; };	
};

struct ZuGross:public Ausnahme {
	int size;		// für zu korrigierende Größe
	ZuGross(int i):Ausnahme("Index zu groß"), size(i) {};
};

struct SpeicherMangel:public Ausnahme {
	ZuGross:Ausnahme("Kein Speicherplatz mehr") {};
};

int* reserviere(int i) {
	if(i>100)
		throw ZuGross(i);	// Übergabe von size!
	int *ip=new int[i];
	if(ip==NULL)
		throw SpeicherMangel;	// ruft alle Destruktoren des 
	return ip;			// try-Blocks auf!
};

void main() {
	int *ip;
	try {
		ip=reserviere(101);
	}
	catch (ZuGross &zg) {		// catch(...) würde alles Abfangen	
		// Fehlerausgabe			
		cout << zg.txtp << endl;
		// Fehlerkorrekturmaßnahmen vor Ort, weil ein
		// Rücksprung zum Fehlerort nicht möglich ist.
		// Der nächste catch-Block wird nicht untersucht!
		int i;
		if(sz.size>200)
			i=100;
		else i=50;
		ip=reserviere(i);	// Größen-Kontrolle müßte in einem
	}				// umschließenden try-Block stattfinden
	catch (Ausnahme &a) {			// Basiklasse erfaßt auch
		cout << a.txtp << endl;		// abgeleitete Fehlerobj.
		return;	// Abbruch		   ==> dürfen nicht am 
	};					// Anfang stehen!
	// wird ein Fehlerobjekt nicht gefunden,
	// bricht das Programm ab.
	// Ansonsten: Fortsetzung des Programms ...
};

4. Sonstiges

* Wenn ein statisches OOA-Modell anzugeben ist, schließt das die Klassen-Spezifikation nicht mit ein; diese wird erst beim erweiterten statischen Modell relevant!

* Entscheidungsfolge-Diagramme sind in aureichender Größe anzufertigen, so daß jeder Pfeil beschriftet werden kann! Zu beachten ist, daß jede Linie ein Objekt repräsentiert und nicht nur eine Klasse!

* Es gilt: Real World > Problembereich > Systembereich! Normalerweise sind die User außerhalb des Systembereichs anzusiedeln.

* Der jeweilige Zustand bei Zustandsdiagrammen pro Objekt ist durch eine geeignete Variable anzugeben!

* exec() zum Aufruf eines eigenständigen, kompilierten Programms ist nach fork() nur nötig, wenn der Sohn-Code nicht im Vater-Code integriert worden ist.

* Signalsetzung:

void fA(){...};
void fB(){...};
void fC(){...};

void g1() {
	signal(sigint, fA());
	...;
};

void g2() {
	g1();
	signal(sigint, fB()); 
	...;
};

void main() {
	signal(sigint, fC());
	g2();
	signal(sigint, fA());
	while(1)
		;
};

Wird bei obigem Programm in der while-Schleife ein sigint ausgelöst, z.B. durch ein Control-C-Ereignis, so wird der Signal-Stack abgebaut, d.h. die Signal-Funktion fA(), fB() und fC() werden in folgender Reihenfolge abgearbeitet:

fA()	->	fB()	->	fA()	->	fC()

* NIH-Besonderheiten:

Task::Task(...):HeapProc(...) {
	if(FORK() != 0) {		// UNIX-fork() genauso!
		// Vater-Prozedur
		...
	};
	// Sohn-Prozedur oder exec()
	...
};

void main() {
	MAIN_PROZESS(priorität);	// erhält i.d.R. Priorität=0
	...
};

* Funktionsaufruf über Funktionspointer:

int f1() { return 1; };
int f2() { return 2; };
void g1(int &i) { cout << i << endl; };
void g2(int &i) { cout << i*2 << endl; };

typedef int (*fp)();			// Funktions-Pointer
typedef void (*gp)(int&);

void main() {
	fp f[2]; gp g[2];			// Felder mit Funktionspointern

	f[0]=&f1;	f[1]=&f2;
	g[0]=&g1;	g[1]=&g2;

	for(int i=0; i<2; i++) {
		cout << (*f[i])() << endl;	// Ausgabe von f1 und f2
		(*g[i])(i);			// Ausgabe von g2 und g2
	};
};

* Überladen von Operatoren. Beispiel einer boolschen Klasse:

enum bool {FALSE, TRUE};

struct boolean {
	bool value;
	friend ostream& operator<<(ostream &os, boolean &b) {
		os << (int)b.value;
		return os;
	};
	boolean operator&&(boolean &b) {
		if(value==TRUE && b.value==TRUE)
			value=TRUE;
		else value=FALSE;
		return *this;
	};
	boolean operator||(boolean &b) {
		if(value==TRUE || b.value==TRUE)
			value=TRUE;
		else value=FALSE;
		return *this;
	};
	boolean operator=(bool &b) {	value=b;	return *this;};
	boolean operator=(boolean &b) {	value=b.value;	return *this;};
};

void main() {
	boolean a, b;
	a=FALSE;
	b=TRUE;
	cout << a << "  " << b << endl;
	cout << (a && b) << endl;
	cout << (a || b) << endl;
	cout << endl;
};

| Home | News | Software | Bilder | Texte | Börse | Favoriten | Goddesses | Winsock | Diplomarbeit | Titel | Inhalt | Einleitung | Kapitel 2 | Kapitel 2-1 | Kapitel 2-2 | Kapitel 2-3 | Kapitel 3 | Kapitel 3-1 | Kapitel 3-2 | Kapitel 3-3 | Ausblick | Literatur | Anhang | Alles fliesst | Comics | Musik | Leben | Links | Sitemap | Admin |

© by DanPHPEd - Letzte Änderung: 21. April 2009