Sonntag der 27. Februar 2011
admin
Das Adapter Pattern dient dazu, eine Klasse (Adaptee) wieder zu verwenden, indem man sie mittels eines Adapters zu einem von einer Anwendung geforderten Interface (Target) kompatibel macht. Dabei hat der Adapter in der objektorientierten Programmierung genau die selbe Bedeutung wie der Adapter im Alltag. Z.B. passt mein deutscher Rasierer prima in eine deutsche Steckdose. Genauso prima passt ein amerikanischer Rasierer in eine amerikanische Steckdose. Beide Steckdosen haben ihre absolute Daseinsberechtigung. Ich möchte für meinen deutschen Rasierer nicht die amerikanische Steckdose aus der Wand reißen, sondern ich passe einfach meinen Rasierer mittels eines Adpters an. Übertragen auf die Softwareentwicklung bedeutet es, dass ich eine bestimmte Klasse wieder verwenden möchte. Ich möchte oder kann die Implementierung der Klasse aber nicht ändern. Z.B. fehlt mir bei einer gekauften Bibliothek der Quellcode. Es ist aber sehr oft auch gar nicht erstrebenswert die für eine allgemeine Bibliothek verfasste Klasse für jeden Anwendungsfall zu spezialisieren. Ich will die existierende Klasse aber auch nicht neu implementieren. Das können andere besser. Oder meine bestehenden Klassen, die das Zielinterface implementieren und die wieder zu verwendende Klasse sind mir schon genug des Guten. Für diese Fälle benutze ich einen Adapter.
Beispiel in C#:
using System;
using System.Diagnostics;
namespace AdapterPattern
{
class Adaptee
{
public int CalculateCaloriesPerDay()
{
// Complicated Legacy Calculation
return 50;
}
}
interface ITarget
{
int GetKCalPerDay();
}
class ClassAdapter : Adaptee, ITarget
{
public int GetKCalPerDay()
{
return CalculateCaloriesPerDay();
}
}
class ObjectAdapter : ITarget
{
public ObjectAdapter(Adaptee adaptee)
{
_adaptee = adaptee;
}
private Adaptee _adaptee;
public int GetKCalPerDay()
{
if (_adaptee == null)
return -1;
return _adaptee.CalculateCaloriesPerDay();
}
}
class Client
{
static void Main()
{
Adaptee caloriesCalculator = new Adaptee();
ITarget cAdapter = new ClassAdapter();
ITarget oAdapter = new ObjectAdapter(caloriesCalculator);
Debug.Assert(cAdapter.GetKCalPerDay() == oAdapter.GetKCalPerDay());
}
}
}
Der Klassenadapter wird von Target und Adaptee abgeleitet. Dadurch adaptiert er genau nur den Adaptee. Zumindest C# unterstützt keine direkte Mehrfachvererbung. Die Adaptierung erfolgt zur zur Kompilierzeit. Die Adaptierung ist aber einfacher als beim Objektadapter. Bei letzterem bestücke ich meinen Adapter per Komposition mit dem Adaptee. Das kann zur Laufzeit geschehen und ich kann mehrere Adaptees adaptieren.
Kategorisiert in Programmierereien
Donnerstag der 24. Februar 2011
admin
Das Command-Pattern dient dazu, einen Aufruf in einem Objekt zu verpacken. Aufrufer können so zur Laufzeit mit Aufrufen bestückt werden. Aufrufe können wieder verwendet und in Listen gehalten werden. Dadurch können Aufrufe zu Makros kombiniert oder nacheinander rückgängig (Undo) gemacht werden. Aufrufer werden von aufgerufenem Empfänger strikt getrennt.
Beispielcode (C#):
using System;
using System.Collections;
namespace CommandPattern
{
public class Player
{
private int _xpos;
public int XPos
{
get { return _xpos; }
set
{
_xpos = value;
Console.WriteLine("XPos = {0}, YPos = {1}", _xpos, _ypos);
}
}
private int _ypos;
public int YPos
{
get { return _ypos; }
set
{
_ypos = value;
Console.WriteLine("XPos = {0}, YPos = {1}", _xpos, _ypos);
}
}
}
public interface ICommand
{
void Execute();
void Undo();
}
public class CommandMoveUp : ICommand
{
private Player _player;
public CommandMoveUp(Player player)
{
_player = player;
}
public void Execute()
{
_player.YPos += 1;
}
public void Undo()
{
_player.YPos -= 1;
}
}
public class CommandMoveDown : ICommand
{
private Player _player;
public CommandMoveDown(Player player)
{
_player = player;
}
public void Execute()
{
_player.YPos -= 1;
}
public void Undo()
{
_player.YPos += 1;
}
}
public class CommandMoveLeft : ICommand
{
private Player _player;
public CommandMoveLeft(Player player)
{
_player = player;
}
public void Execute()
{
_player.XPos -= 1;
}
public void Undo()
{
_player.XPos += 1;
}
}
public class CommandMoveRight : ICommand
{
private Player _player;
public CommandMoveRight(Player player)
{
_player = player;
}
public void Execute()
{
_player.XPos += 1;
}
public void Undo()
{
_player.XPos -= 1;
}
}
public class MoveControl
{
public CommandMoveDown MoveDownCommand { get; set; }
public CommandMoveUp MoveUpCommand { get; set; }
public CommandMoveLeft MoveLeftCommand { get; set; }
public CommandMoveRight MoveRightCommand { get; set; }
private Stack _commandStack = new Stack();
public void MoveUp()
{
MoveUpCommand.Execute();
_commandStack.Push(MoveUpCommand);
}
public void MoveDown()
{
MoveDownCommand.Execute();
_commandStack.Push(MoveDownCommand);
}
public void MoveLeft()
{
MoveLeftCommand.Execute();
_commandStack.Push(MoveLeftCommand);
}
public void MoveRight()
{
MoveRightCommand.Execute();
_commandStack.Push(MoveRightCommand);
}
public void Undo()
{
if (_commandStack.Count == 0)
return;
Console.WriteLine("Undo:");
var command = (ICommand)_commandStack.Pop();
if (command != null)
command.Undo();
}
}
class Client
{
static void Main(string[] args)
{
var receiver = new Player();
var moveUpCommand = new CommandMoveUp(receiver);
var moveDownCommand = new CommandMoveDown(receiver);
var moveLeftCommand = new CommandMoveLeft(receiver);
var moveRightCommand = new CommandMoveRight(receiver);
KeyboardControl invoker = new KeyboardControl();
invoker.MoveUpCommand = moveUpCommand;
invoker.MoveDownCommand = moveDownCommand;
invoker.MoveLeftCommand = moveLeftCommand;
invoker.MoveRightCommand = moveRightCommand;
while (true)
{
System.ConsoleKeyInfo KInfo = Console.ReadKey(true);
switch (KInfo.Key)
{
case ConsoleKey.UpArrow:
invoker.MoveUp();
break;
case ConsoleKey.DownArrow:
invoker.MoveDown();
break;
case ConsoleKey.LeftArrow:
invoker.MoveLeft();
break;
case ConsoleKey.RightArrow:
invoker.MoveRight();
break;
case ConsoleKey.Spacebar:
invoker.Undo();
break;
}
}
}
}
}
Das Bild zeigt, dass Undo verlässlich funktioniert:

Der längliche Code spiegelt eine Eigenheit des Musters nieder. Da Befehle so eingekapselt werden, dass sie nur noch über die Methoden Execute() und Undo() verfügen, gibt es entsprechend viele Befehlsklassen. Im Beispiel erzeugt Client 4 Befehle, um eine Spielfigur jeweils 1 Schritt nach oben, unten, rechts und links gehen zu lassen. Den Befehlen wird ein ebenso erzeugter Receiver (Player) verpasst. Mit diesen Befehlen wird ein Invoker (MoveControl) bestückt (parametrisiert). MoveControl merkt sich alle aufgerufenen Befehle in einem Stack, so das auf Undo-Wunsch Undo() auf den Befehlen aufgerufen werden und diese wieder vom Stack genommen werden können.
In diesem Beispiel ist die Anzahl der Befehle noch überschaubar. Man kann sich leicht komplexere Beispiele, wie einen Rechner vorstellen, der über endlose Befehle verfügen kann wie Rechne5mal5, Rechne5mal6, Rechne1plus2, … Hier kommt man nicht umhin, für jede Anfrage des Benutzers zur Laufzeit einen neuen Befehl zu erzeugen, z.B. new CalculateCommand (string operator, double operand) und dem Invoker unterzujubeln, bevor man diesen den Befehl aufrufen lässt. Nur so können Invoker und Receiver getrennt bleiben.
Kategorisiert in Programmierereien
Donnerstag der 17. Februar 2011
admin
Das Singleton-Objekt existiert nur einmal. Das wird dadurch sicher gestellt dass der Konstruktor der Singletonklasse privat ist. Um eine Instanz zu erzeugen, existiert eine statische Elementfunktion, die einer Instanzvariablen, falls diese uninitialisiert ist, eine Instanz von Singleton zuweist und diese zurück gibt. Ein Objekt wird also nur erzeugt, wenn es benötigt wird und das genau einmal.
Wird diese Klasse von verschiedenen Threads benutzt, gibt es zusätzlich einiges zu beachten, welches ich dann bei Bedarf nachlesen werde.
Ein großer Nachteil beim Singleton besteht darin, dass er die von der Objektorientierung favorisierte Kapselung für seine Einzigartigkeit opfert. Ein Singleton ist global verfügbar und jeder kann das Objekt manipulieren, falls es über öffentliche Setter verfügt. Hier muss man wie bei allem Vorteile und Nachteile abwägen. Man sollte den Singleton also nur einsetzen, wenn das Bedürfnis überwiegt, sicher zu stellen, dass genau eine Instanz des Singleton existiert.
Kategorisiert in Programmierereien
Dienstag der 15. Februar 2011
admin
Die abstrakte Fabrik hatte ich ja schon. Aber was ist der Unterschied zur Fabrikmethode? Ich zitiere aus Objektorientierte Programmierung – Das umfassende Handbuch:
- Die Fabrikmethode existiert nicht an einer eigens dafür erstellten Klasse, sondern sie ist eine zusätzliche Methode in einer bereits existierenden Klassenhierarchie.
- Die erzeugenden Klassen haben in der Regel eine konkrete technische oder fachliche Aufgabenstellung. Im Rahmen dieser Aufgabenstellung benötigen sie Exemplare von Klassen, die in einer dazu korrespondierenden parallelen Hierarchie aufgebaut sind.
- Die konkreten abgeleiteten Klassen der Erzeuger nutzen nun die Fabrikmethode, um Exemplare der jeweils benötigten konkreten Produktklassen zu erstellen.
Auch abstrakte Fabriken nutzen in der Regel Fabrikmethoden, um ihre Produkte zu erzeugen. Der entscheidende Unterschied ist aber: Die Klassenhierarchie, die für die abstrakte Fabrik aufgebaut wird, hat ausschließlich den Zweck, diese Produkte zu erzeugen.
Beispiel: Die Fabrikmethode GetEnumerator() gehört dem IEnumerable Interface an und liefert einen IEnumerator. Die das IEnumerable implementierende Klassenhierarchie, zu der z.B. ArrayList, Dictionary oder List gehören, hat die Aufgabe, mit Collections umzugehen. Dazu ist ein Iterator unerlässlich. In Patternsprache bedeutet das: Eine konkrete Fabrik z.B. ArrayList gibt per GetEnumerator() einen konkreten Iterator ArrayListEnumeratorSimple zurück, welcher vom Klienten über das IEnumerator Interface benutzt wird.
Kategorisiert in Programmierereien
Samstag der 12. Februar 2011
admin
Der Dekorierer dient dazu, eine Komponente zu erweitern, ohne sie zu verändern. Es setzt eben dieses OCP (Open Closed Principle) in seiner reinsten Form um: Ein Objekt zu erweitern ohne es zu verändern. Es wird eingesetzt, wo eine Klassenhierarchie eine Klassenexplosion ergeben würde. Dekoratoren, die eine Komponente ergänzen, stellen einen Baukasten zur verfügung, dessen Bausteine frei nach Wunsch zur Laufzeit zusammengebaut werden können, um das gewünschte Verhalten der Komponente zu definieren. Dekorierer wie Komponente implementieren dasselbe Interface, und der Dekorierer wird mit einer Instanzvariable (HAS-A) der Komponente bestückt. Die Komponente kann widerum ein Dekorierer sein, weshalb sich Dekorierer endlos schachteln können. Wird nun eine Komponentenmethode des Dekorierers aufgerufen, wird der Aufruf an das eingeschlossene Komponentenobjekt weitergeleitet. Ist die Komponente ein Dekorierer, wird der Aufruf wiederum weiter geleitet bis er bei der gekapselten Komponente ankommt.
Ich tippe mal das Beispiel aus dem Head First Design Patterns-Buch ab und setze einen Dekorierer oben drauf. Hier der Java-Code:
import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
class CountInputStream extends FilterInputStream
{
public int Count = 0;
public CountInputStream (InputStream in)
{
super (in);
}
public int read() throws IOException
{
Count ++;
return super.read();
}
}
class LowerCaseInputStream extends FilterInputStream
{
public LowerCaseInputStream (InputStream in)
{
super(in);
}
public int read() throws IOException
{
int c = super.read();
return (c == -1) ? c : Character.toLowerCase((char)c);
}
}
public class Decorator
{
public static void main (String argv[])
{
int c;
try
{
InputStream in =
new CountInputStream(
new LowerCaseInputStream(
new BufferedInputStream(
new FileInputStream("test.txt"))));
while ((c = in.read()) >= 0)
{
System.out.print((char)c);
}
System.out.println(((CountInputStream)in).Count);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Zusätzlich zum puren Einlesen aus einer Datei, werden große Zeichen gedemütigt und zu kleinen umgewandelt. Durch meinen eigens aufgesetzten Dekorierer werden die Buchstaben mitgezählt.
Das Dekorierer-Muster weist Ähnlichkeiten zum Strategie-Pattern auf. Man könnte die dynamischen Eigenschaften auch realisieren, indem man der Komponente eine Liste von Eigenschaften gibt. Natürlich ist die Komponente dann nicht mehr so ganz geschlossen und kennt immer noch das Interface der Eigenschaften. Das GoF-Buch sagt dazu: Changing the skin of an object versus changing its guts. Während die Strategie darin besteht, ein wesentliches Verhalten (Eingeweihde) einer Komponente zur Laufzeit austauschen zu können, zielt das Dekorierer-Muster darauf ab, oberflächliches Verhalten (Haut) zu kapseln.
Kategorisiert in Programmierereien
Dienstag der 8. Februar 2011
admin
Beim Observer-Pattern geht es darum 1-n Objekte von der Zustandsänderung eines Subjekts in Kenntnis zu setzen, und das in möglichst lose gekoppelter weise.
Beispiel: In einer Autorenn-Simulation gibt es eine Ampel und verschiedene Autos. Wenn die Ampel ihren Zustand ändert, also rot, organge oder grün wird, sendet sie an alle als Observer registrierten Autos ein Update(). Als Argument übergibt sie sich selbst, so dass das Auto-Objekt dann denn Zustand lesen und entsprechend darauf reagieren kann. Wenn beispielsweise die Ampel auf rot springt, das Auto fährt, und es sich in der Nähe der Ampel befindet, muss es anhalten.
Beispielcode in C#:
using System;
using System.Collections.Generic;
namespace ObserverPattern
{
public interface Observer
{
void Notify (Observable observable);
}
public interface Observable
{
void Register (Observer observer);
void Remove (Observer observer);
void NotifyObservers();
}
public enum Color {Red, Orange, Green};
public class TrafficLight : Observable
{
public TrafficLight(double x, double y)
{
X = x;
Y = y;
}
public double X { get; set; }
public double Y { get; set; }
Color _color = Color.Green;
public Color Color
{
get { return _color; }
set
{
_color = value;
NotifyObservers();
}
}
List<Observer> _observers = new List<Observer>();
public void Register (Observer observer)
{
_observers.Add(observer);
}
public void Remove (Observer observer)
{
_observers.Remove(observer);
}
public void NotifyObservers()
{
foreach (Observer observer in _observers)
observer.Notify(this);
}
}
public class Car : Observer
{
public Car(double x, double y)
{
X = x;
Y = y;
}
public double X { get; set; }
public double Y { get; set; }
public void Notify(Observable observer)
{
if (! (observer is TrafficLight))
return;
TrafficLight tlight = (TrafficLight)observer;
double diffX = Math.Abs(X-tlight.X);
double diffY = Math.Abs(Y-tlight.Y);
if (tlight.Color == Color.Red)
{
if (diffX < 5 || diffY < 5)
Console.WriteLine ("Time to stop!");
else
Console.WriteLine ("Go on!");
}
}
}
class MainClass
{
public static void Main (string[] args)
{
Car oldtimer = new Car(15,16);
Car rocketCar = new Car(30,40);
TrafficLight tlight = new TrafficLight(10,20);
tlight.Register(oldtimer);
tlight.Register(rocketCar);
tlight.Color = Color.Red;
}
}
}
Die sich ändernden Aspekte des Codes, nämlich der Zustand und die Anzahl der Observer werden Im Subjekt TrafficLight gekapselt. Subjekt wie Objekte implementieren Interfaces und es werden keine Klassen abgeleitet, sondern die Interaktion zwischen Subjekt und Objekten findet per Komposition statt. Zusätzlich sind beide Klassen lose gekoppelt. Das Subjekt kennt die Objekte nicht persönlich, sondern nur deren Interface. Objekte können jegliche Gestalt annehmen, solange sie nur das Interface implementieren. Das Subjekt kann zur Laufzeit beliebige Objekte als Observer aufnehmen und entfernen.
Kategorisiert in Programmierereien
Sonntag der 6. Februar 2011
admin
Abstrakte Fabrik – das hört sich am kompliziertesten an, also weiter damit. Die abstrakte Fabrik ist ein Erzeugungsmuster und dient dazu, sich von der Erzeugung ganzer Produktfamilien unabhängig zu machen. Ein prominentes Beispiel sind Fabriken zur Erzeugung von Betriebssystemabhängigen Oberflächenelementen. Es könnte eine Fabrik MSFactory und eine Fabrik MacFactory geben, die beide verschiedene Familien von Oberflächenelementen zu Verfügung stellen. Da auch die Produkte dieselbe Schnittstelle besitzen (z.B. Fenster verschieden, oder Größe ändern), kann die Fabrik gewechselt werden, um die Software auf verschiedenen System laufen zu lassen.
Ich habe mir ein anderes Beispiel einfallen lassen. Ich denke da an ein Ayurveda-Kurhotel, in dem Gäste in drei Gruppen gemäß ihrem Dosha eingeteilt werden und eine Diät machen. Das Bedienungspersonal soll sich nicht um die Erzeugung der Mahlzeiten Gedanken machen müssen, sondern nur wissen, um welche Tageszeit es sich handelt und welches das Dosha des Gastes ist. Deshalb gibt es für die Doshas Kapha, Vata und Pitta jeweils eine eigene Factory, die Frühstück, Mittagessen und Abendessen erstellt.
Hier der Code (C#):
using System;
namespace AbstractFactoryPatternExample
{
public interface IAyurvedaMealFactory
{
IBreakfast CreateBreakfast();
ILunch CreateLunch();
ISupper CreateSupper();
}
public interface IBreakfast{}
public interface ILunch{}
public interface ISupper{}
public class KaphaBreakfast : IBreakfast{}
public class PittaBreakfast : IBreakfast{}
public class VataBreakfast : IBreakfast{}
public class KaphaLunch : ILunch{}
public class PittaLunch : ILunch{}
public class VataLunch : ILunch{}
public class KaphaSupper : ISupper{}
public class PittaSupper : ISupper{}
public class VataSupper : ISupper{}
class KaphaMealFactory : IAyurvedaMealFactory
{
public IBreakfast CreateBreakfast()
{
return new KaphaBreakfast();
}
public ILunch CreateLunch()
{
return new KaphaLunch();
}
public ISupper CreateSupper()
{
return new KaphaSupper();
}
}
class PittaMealFactory : IAyurvedaMealFactory
{
public IBreakfast CreateBreakfast()
{
return new PittaBreakfast();
}
public ILunch CreateLunch()
{
return new PittaLunch();
}
public ISupper CreateSupper()
{
return new PittaSupper();
}
}
class VataMealFactory : IAyurvedaMealFactory
{
public IBreakfast CreateBreakfast()
{
return new VataBreakfast();
}
public ILunch CreateLunch()
{
return new VataLunch();
}
public ISupper CreateSupper()
{
return new VataSupper();
}
}
class MainClass
{
public static void Main (string[] args)
{
Console.WriteLine ("It's morning time and there is a kapha tourist");
Console.WriteLine ("Creating kapha breakfast ...");
IAyurvedaMealFactory kaphaFactory = new KaphaMealFactory();
IBreakfast breakfast = kaphaFactory.CreateBreakfast();
Console.WriteLine(breakfast.ToString());
Console.WriteLine ("\nIt's noon and there is a pitta tourist");
Console.WriteLine ("Creating pitta lunch ...");
IAyurvedaMealFactory pittaFactory = new PittaMealFactory();
ILunch lunch = pittaFactory.CreateLunch();
Console.WriteLine(lunch.ToString());
}
}
}
Das Interface des Produkts könnte man natürlich benutzen, um Rezepte oder Verzehrempfehlungen zu speichern. Nachteil des Musters: Man muss für jedes Produkt alle Fabriken erweitern. Jede neue Fabrik muss alle Produkte herstellen.
Kategorisiert in Programmierereien
Sonntag der 6. Februar 2011
admin
Eine Frage hat mich neulich verblüfft: Welche Design Patterns benutzt du denn so? Obwohl ich umbewusst bestimmt etwas von Design verstehe, kann ich es nicht in Worte fassen. Und dazu dienen ja auch Design Patterns, nämlich um über ein gemeinsames Vokabular bezüglich des Softwaredesigns zu verfügen. Also jetzt werden die Patterns systematisch gepaukt. In meiner unterhaltsamen Ausgabe der Design Patterns, nämlich ‘Head first Design Patterns’ geht es zuerst um das Strategie-Muster. Es ist wohl deswegen so grundlegend, weil es gleich 3 Designprinzipien realisiert.
Hier ein Codebeispiel in C#:
using System;
namespace StrategyPatternExample
{
public interface IHeatingDemandCalculator
{
void Calculate();
}
public class SwitzerlandHeatingDemandCalculator : IHeatingDemandCalculator
{
public void Calculate()
{
Console.WriteLine("Calculating heating demand the switzerland way!");
}
}
public class GermanyHeatingDemandCalculator : IHeatingDemandCalculator
{
public void Calculate()
{
Console.WriteLine("Calculating heating demand the german way!");
}
}
public class House
{
public House()
{
_heatingDemandCalculator = new GermanyHeatingDemandCalculator();
}
IHeatingDemandCalculator _heatingDemandCalculator;
public void HeatingDemandCalculator(IHeatingDemandCalculator calculator)
{
_heatingDemandCalculator = calculator;
}
public void CalculateHeatingDemand()
{
_heatingDemandCalculator.Calculate();
}
}
class MainClass
{
public static void Main (string[] args)
{
House house = new House();
house.CalculateHeatingDemand();
house.HeatingDemandCalculator(new SwitzerlandHeatingDemandCalculator());
house.CalculateHeatingDemand();
}
}
}
Für ein Haus soll ein Wärmebedarf berechnet werden.
Die einfachste Möglichkeit wäre, die Berechnung direkt in dieser Klasse in Code zu gießen. Momentan gibt es nur diese eine Klasse. Kommen später jedoch abgeleitete Klassen wie Bungalow oder Mehrfamilienhaus oder Hochhaus hinzu, erben sie alle die selbe Wärmebedarfsberechnung. Wieso nicht? Man kann jetzt vielleicht noch gar nicht sagen, ob diese Berechnung so wichtig ist, dass alle abgeleitete Klassen sie erben müssen. Jede Unterklasse möchte vielleicht die Berechnung anders implementieren. Kommen noch andere Berechnungen hinzu, werden die im selben Maße vererbt. Vielleicht gibt es auch Modellhäuser, die über gar keine Berechnung verfügen sollen, sondern nur der Visualisierung dienen. Dann stehen in der Basisklasse Fallunterscheidungen an, aber den Code möchte man nicht ändern.
Als nächste Möglichkeit, kann eine Berechnung in der abgeleiteten Klasse definiert werden. Dann ists aber mit der Wiederverwendbarkeit dahin. Denn Code wird für 97% der Unterklassen wiederholt.
Hat man einmal das Design Pattern gesehen, gibt es keine andere Lösung: Die Basisklasse bekommt einen Interfacepointer auf IHeatingDemandCalculator, welcher vererbt wird. Sowohl Basisklasse als auch abgeleitete Klassen können die konkrete Implementierung der Berechnung wechseln und gemäß dem Interface immer calculate aufrufen. Nun können für Bungalows, Mehrfamilienhäuse oder Hochhäuser der Wärmebedarf entweder nach deutschem oder schweitzerischen Recht berechnet werden.
Diese Flexibilität erhalten wir dadurch, dass wir 3 grundlegende Designprinzipien berücksichtigt haben:
- Identifizere sich ändernde Aspekte und trenne sie von gleich bleidenden Programmteilen
- Programmiere gegen ein Interface, nicht gegen die Implementierung
- Ziehe Komposition der Vererbung vor
Kategorisiert in Programmierereien
Sonntag der 2. Januar 2011
admin
Nachdem ich die Machbarkeit eines Webservice erkundet habe, mache ich mich nun an die Implementierung eines Teils der Oberfläche und der Portierung der Logik von meiner letzten Entwicklung eines SGF-Players mit Java.
Als Erstes verpacke ich meine Oberfläche in ein Grid-Layout. Eine Zelle beherbergt eine ViewBox-Element. Wie in SVG werden Inhalte dieser Box skaliert, je nachdem, wieviel Platz sie innerhalb des Gitters im Browserfester zu Verfügung bekommt. Trotzdem kann die Box ein Rectangle in einem Canvas beinhalten, welches 1000 x 1000 Pixel groß ist. Auch wenn die tatsächliche Größe des Rechtecks abweicht, kann ich im Code mit dieser Größe rechnen. Auf diese Weise kann ich ganz einfach meinen Java Code portieren, der ebenfalls mit dieser Größe arbeitet.
Obwohl XAML keinen Standard für Vektorgrafik bietet, kann ich die Konzepte meiner Grafikgenerierung, die ich mit der SVG basierten Java-Bibliothek Batik entwickelt habe, übernehmen. Das Muster des Go-Bretts kommt durch eine große Textur zustande, ein Foto meiner Schreibtischplatte. Das bringt mir 500 KB Übertragungsoverhead ein. Aber in Zeiten der schnellen Leitungen kann ich eine Optimierung verzögern.
Die Portierung der Logik verlief am poblemlosesten. Ich kopierte meinen Java Code mit sehr wenigen Änderungen nach C#. Ich musste etwa die Syntax für mehrdimensionale Arrays oder von Stringoperationen ändern. Ein vollständiges Austauschen der for- in die besser lesbaren und eleganteren foreach-Anweisungen konnte ich mir nicht verkneifen.
Unter Windows flutscht die Anwendung. Rückmeldungen eines Mac-nutzenden Kumpels sind ebenfalls sehr positiv. Die Steine werden fast genauso schnell gesetzt, wie ich klicken kann. Als böse Überraschung finde ich unter Linux Unebenheiten vor. Auf meinem Rechner stellt Moonlight die Steine nicht korrekt dar. Auf dem Rechner meine Frau tut Moonlight es, dafür fehlen bei beiden Rechnern die Schatten. Installiere ich Moonlight 3, wird zwar alles korrekt dargestellt, aber die CPU-Auslastung ist sehr hoch, auch wenn die Anwendung ruhen sollte. Die Frickelei, um herauszufinden, woran es hapert, spare ich mir im Urlaub. Im Forum von go-mono.com habe ich mein Problem geschildert, wieder ohne Antwort. Das erfüllt mich nicht mit Vertrauen und ich hadere einen Moment.
Warum andererseits trauern? Meine Zielgruppe sind Clientnutzer und die benutzen zu 99,1 % Windows oder Macintosh. Es gibt laut Net Market Share nur 0,9% Linuxinstallationen auf dem Desktop. Und hier geht es ja nicht um Jesus, der seine 99 Schafe zurücklässt, um ein verlorenes Schaf zu retten. Und vielleicht macht sich Moonlight ja noch. Und wer interessiert sich schon für Go?
Hier die Anwendung. Die inhaltliche Benutzbarkeit muss natürlich erst noch hergestellt werden.
Kategorisiert in Programmierereien
Mittwoch der 22. Dezember 2010
admin
Ich mag Silverlight. Es wurde tatsächlich von Microsoft mit dem Anspruch entwickelt, plattformunabhängig zu sein. Da Microsoft der .NET-Nachbildung Mono seit den Anfängen von Mono bisher keinerlei Beschränkungen auferlegt hat, ist auch später nicht mit Patentklagen zu rechnen.
Als Demoanwendung will ich wieder einen SGF-Player entwickeln, diesmal fürs Web. Da Unmassen von Go-Spielen nicht bei jedem Aufruf des Players auf den Client geladen werden können, komme ich um einen Webservice nicht herum. Denn Silverlight ist eine Clienttechnologie und kann keine direkte Datenbankverbindung aufbauen.
Ich würde gerne in Silverlight mit meinem privaten Lieblingsbetriebssystem, Linux, entwickeln. Daher probiere ich mit MonoDevelop, einen Webservice zu programmieren. Auf www.webservicex.net finde ich einen Service, der das Symbol eines Unternehmens entgegen nimmt und mir die Aktienwerte zurück gibt.
Informationen, wie ich einen Webservice mit unter Mono entwickele sind spärlich aber ich finde ein repräsentatives Beispiel von Mono selbst. Lege ich mit MonoDevelop ein Moonlight-Projekt an und füge ich eine Webreferenz auf die Adresse des Service hinzu, wird zwar die WSDL (Web Service Description Language)-Datei des Service gefunden und es werden Servicezugriffsklassen generiert. Aber, oh Schande: der generierte Code lässt sich nicht übersetzen. Der Namespace der Zugriffsschicht ist ein ‘.’ und der Code benutzt den Namespace System.Web.Service, welcher in Silverlight nicht existiert. Auf meine Schilderung meines Problems im Forum von www.go-mono.com bekomme ich keine Antwort.
Danke, das wars dann. Ich versuche mein Glück mit dem Visual Studio unter Windows. Es gibt Beispiele wie Sand am Meer und ich kann meinen Service problemlos entwickeln.
Folgenden Codeschnipsel habe ich geschrieben, nachdem ich eine Servicereferenz auf den Webservice gesetzt habe und die Zugriffsklassen fehlerfrei generiert wurden.
Hier der C#-Code:
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
ServiceReference1.StockQuoteSoapClient proxy = new ServiceReference1.StockQuoteSoapClient();
//Wire the proxy to a completed handler to allow the async operation to be handled
proxy.GetQuoteCompleted +=
new EventHandler&amp;amp;amp;lt;ServiceReference1.GetQuoteCompletedEventArgs&amp;amp;amp;gt;(
proxy_GetCustomerCompleted);
//Call the service asynchronously
proxy.GetQuoteAsync(&amp;amp;amp;quot;GOOG&amp;amp;amp;quot;);
}
void proxy_GetCustomerCompleted(object sender, ServiceReference1.GetQuoteCompletedEventArgs e)
{
//Bind the returned data to the DataContext
System.Windows.Browser.HtmlPage.Window.Alert(e.Result.ToString());
}
}
}
Die Antwort des Webdienstes auf “GOOG” ist nachfolgend in XML abgebildet.

Eine Silverlight-Anwendung wird publiziert, indem einfach die HTML- und die dazu gehörige XAP-Datei auf den Server kopiert werden. Das Schöne: Die Anwendung ist tatsächlich plattformunabhängig. Unter Linux funktioniert die Anwendung genauso wie unter Windows. Unter Linux zwar mit einer Meldung, dass es sich um eine Silverlight 3-Anwendung handelt, Moonlight jedoch erst Silverlight 2 abdeckt. Es sei also mit Imkompatibilitäten zu rechnen. Das stört mich allerdings weniger, da die nächste Moonlight Version Silverlight 3 abdecken und im 1. Quartal 2011 heraus kommen soll.
In einer Antwort in einem Forum auf www.go-mono.com habe ich gelesen, dass sich das Mono-Team bisher hauptsächlich auf die Lauffähigkeit von Mono-Anwendungen konzentriert hat statt auf das Bereitstellen einer funktionstüchtigen IDE. Die Erfahrung habe ich hiermit auch gemacht.
Kategorisiert in Programmierereien