Interface Segregation Principle

Die Kernaussage des Interface Segregation Principles – ISP (dt. Schnittstellenaufteilungsprinzip ) ist, dass Schnittstellen keine Methoden enthalten sollen, die von implementierenden Klassen nicht verwendet werden (können).

Eine einsame Katze

Ausgangspunkt ist die Klasse Katze. Sie enthält Methoden zum Essen, Miauen und zerstören von teuren Dingen, das was Katzen nun mal so anstellen.

UML


Cat Class

C#

    public class Cat
    {
        public void Eat()
        {
            //eat some nice fish
        }

        public void MakeSound()
        {
            //MEOW!
        }

        public void ThrowDown(object expensiveObject)
        {
            //Destroy object by accelerating it towards the ground
        }
    }

JAVA

Liskov Substituion Principle

Einführung

1987 wurde das Liskov Substituion Principle (LSP), oder zu deutsch Liskovsche Substitutionsprinzip, von Barbara Liskov vorgestellt. Es ist eine spezielle Regelung für Subtypisierung von Klassen und besagt:

Ein Programm, das Objekte einer Basisklasse verwendet muss auch mit davon abgeleiteten Klassen funktionieren ohne, dass das die Funktion eingeschränkt wird.

Ist-Eine-Beziehung

Wird eine neue Klasse von einer bestehenden Klasse abgeleitet, erbt die neue Klasse sämtliche Eigenschaften und Methoden. Neue Methoden und Eigenschaften werden dann zu den bestehenden hinzugefügt und können auf diese zugreifen. Hierbei spricht man meist von einer Ist-Eine-Beziehung. Beispielsweise wäre die Klasse Cat von der Basisklasse Animal abgeleitet. Die Beziehung würden dann „Eine Katze ist ein Tier“ lauten und damit die Ableitung begründen.

Open Closed Principle

Einführung

Das Open-Closed-Prinzip (Prinzip der Offen- und Verschlossenheit) kurz OCP wird von Bertrand Meyer wie folgt beschrieben:

„Module sollten sowohl offen für Erweiterungen,
als auch verschlossen für Modifikationen sein“.

Dies bedeutet, dass das Verhalten eines Moduls (Klasse, Methode …) erweitert werden kann, ohne den Ursprünglichen Quellcode verändern zu müssen. Die ursprüngliche Version eines Moduls wird demnach nicht mehr bearbeitet sondern das Verhalten in künftigen Versionen lediglich erweitert.

Am Beispiel einer kompilierten Klassenbibliothek würde eine Erweiterung durch eine Ableitung stattfinden. Die ursprüngliche Klasse bleibt dabei für Modifikationen verschlossen. Dadurch werden nötige Anpassungen an allen Klassen, welche die Bibliothek verwenden, verhindert.

Single Responsibility Principle

Einführung

Das Single Responsibility Principle (SRP) – zu deutsch „Prinzip der eindeutigen Verantwortlichkeit“ sagt aus, dass jede Klasse oder Modul nur eine einzige Aufgabe innerhalb eines Programmes erledigen soll und dafür nur Funktionen zur Erfüllung dieser Aufgabe enthält. Es ist daher ein Prinzip zur Strukturierung das dem Entwickler erlaubt, Funktionalität logisch zu Gruppieren.

Robert C. Martin, unter anderem Autor der , drückt es folgendermaßen aus:

“There should never be more than one reason for a class to change.”
“Es sollte nie mehr als einen Grund geben, eine Klasse zu ändern.“

Er stützt seine Aussage wiederrum auf das Prinzip der Kohäsion.

Simple Factory

Einführung

„Eine factory (Fabrik) ist ein Objekt um andere Objekte zu erstellen.“

Dieser Satz sagt im wesentlichen alles über das Simple Factory Pattern aus. Anstatt ein Objekt direkt über den Konstruktor zu instanzieren, wird eine spezielle Methode, eine Factory, für diesen Zweck verwendet. Meist findet das Simple Factory Pattern kaum Bedeutung und wird häufig als ein Teil, oder als Grundlage, von komplexeren Pattern verwendet. Beispiele dafür sind Object Libraries oder das Abstract Factory Pattern. Teilweise werden Simple Factories auch nicht als Pattern angesehen sondern eher als eine Grundlage der objektorientierten Programmierung.

Als Factory wird meist eine einzelne Methode bezeichnet, die ein bereits instanziertes Objekt zurückgibt.
Ein simples Beispiel:

C#

        static void Main(string[] args)
        {
            var kittyCat = Animal.CreateCat();

            Console.WriteLine($"My cat is {kittyCat.color} and his name is {kittyCat.name}");
            Console.ReadLine();
        }

        class Animal
        {
            public string name { get; set; }
            public string color { get; set; }

            public static Animal CreateCat()
            {
                var cat = new Animal
                {
                    name = "Kitty",
                    color = "black"
                };
                
                return cat;
            }
        }

JAVA

public class TestClass {

	public static void main(String[] args){
		animal kittyCat = Animal.CreateCat();
		
		System.out.println("My cat is " + kittyCat.getColor() + 
			" and his name is " + kittyCat.getName());
	}
}

public class Animal {
	private String name;
	private String color;
	
	public String getName() { return name; }
	public void setName(String name) { this.name = name; }
	
	public String getColor() { return color; }
	public void setColor(String color) { this.color = color; }
	
	public static Animal CreateCat()
	{
		Animal cat = new Animal();	
		cat.name = "Kitty";
		cat.color = "black";
		
		return cat;
	}
}

Value Object Design Pattern

Einführung

Mit Value Object werden einfache Objekte bezeichnet, bei denen die Werte der Eigenschaften bei einem Vergleich verwendet werden. Es werden also nicht, wie sonst bei Referenztypen üblich, die Identitäten der Objekte verglichen.

C# bietet für dieses Pattern die Möglichkeit  ein Struct zu definieren. Structs sind bereits per Definition Werttypen. Beim Vergleich von Structs werden also die Werte miteinander verglichen. Es bedarf nur kleinen Anpassungen damit es vollends dem Pattern entspricht.

in JAVA existiert hingegen keine Möglichkeit einen benutzerdefinierten Value Type zu erstellen. Früher kam es jedoch vor, dass Data Transfer Objects als Value Objects bezeichnet wurden.

C#

        static void Main(string[] args)
        {
            var catFromStructA = new CatStruct { Name = "Kitty", Color = "Black" };
            var catFromStructB = new CatStruct { Name = "Kitty", Color = "Black" };
            var resultStructs = catFromStructA.Equals(catFromStructB);

            Console.WriteLine($"Struct equation: {resultStructs}");


            var catFromClassA = new CatClass { Name = "Kitty", Color = "Black" };
            var catFromClassB = new CatClass { Name = "Kitty", Color = "Black" };
            var resultClasses = catFromClassA.Equals(catFromClassB);

            Console.WriteLine($"Class equation: {resultClasses}");

            Console.ReadLine();
        }

        public struct CatStruct
        {
            public string Name;
            public string Color;
        }

        public class CatClass
        {
            public string Name;
            public string Color;
        }