Freitag, 27. August 2010

Two out of the crowd

Entwurfsmustern begegnet man häufig bei der Erstellung von Programmen. Entwurfsmuster werden gerne als Schablone für Problemlösungen herangezogen und standardisieren quasi die Programmierung allgemeiner Algorithmen für die Erstellung von Software.

Entwurfsmuster sind Teil der gemeinsamen Sprache unter Entwicklern. Es ist offensichtlich einfacher, einem Entwickler zuzurufen, er solle doch bitte eine Facade programmieren, als mühsam erklären zu müssen, welche Art von Komponente er erstellen soll. Zu dem gemeinsamen Verständnis über die Quellcodequalität gehört deshalb auch ein gemeinsamer Sprachschatz, um klar und deutlich miteinander kommunizieren zu können.

Ein kleiner Teilausschnitt aus dem Katalog der Entwurfsmuster sind die Erzeugungsmuster mit denen Objekte instanziiert werden können. Zu den Erzeugungsmustern gehört die Klasse der Fabriken (Factory Patterns). Fabriken werden immer dann eingesetzt, wenn Objekte auf Basis einer allgemeinen Schnittstelle erstellt werden sollen und dabei auch noch die Konfigurierbarkeit eine Rolle spielt. Zwei Muster aus dem Katalog der Erzeugungsmuster werden nachfolgend im Quellcode veranschaulicht.

Fabrikmuster (Factory Pattern)

Das Fabrikmuster der nachfolgenden Implementierung nutzt die Möglichkeiten des Enumerationstyps, der ab Java 5 ein Sprachelement von Java ist und bei der Implementierung des Musters eine interessante Alternative zu den herkömmlich bekannten Fabrikimplementierungen bietet.

Generische Schnittstelle des Fabrikmusters:

interface Factory<T> {
   
    T instance();
}

Eine Fabrik für Integer-Listen:

import java.util.ArrayList;
import java.util.List;

public enum IntListFactory implements Factory<List<Integer>> {

    NEW {
   
        public List<Integer> instance() {
           
            return(new ArrayList<Integer>());
        }
    };   
}

Eine Fabrik für String-Listen:

import java.util.ArrayList;
import java.util.List;

public enum StringListFactory implements Factory<List<String>> {

    NEW {
   
        public List<String> instance() {
           
            return(new ArrayList<String>());
        }
    };   
}

JUnit-Test des Fabrikmusters:

import static org.junit.Assert.assertEquals;
import java.util.List;
import org.junit.Test;

public class TestFactory {

    private static final int INDEX_OF_FIRST_LIST_ENTRY = 0;
    private static final int INT_TEST_VALUE = 25;
    private static final String STR_TEST_VALUE = "strValue";
   
    @Test
    public void testStringListFactory() {
       
        final List<String> list = StringListFactory.NEW.instance();
        list.add(STR_TEST_VALUE);
       
        assertEquals(STR_TEST_VALUE, list.get(INDEX_OF_FIRST_LIST_ENTRY));       
    }
   
    @Test
    public void testIntListFactory() {
       
        final List<Integer> list = IntListFactory.NEW.instance();
        list.add(INT_TEST_VALUE);
       
        assertEquals(INT_TEST_VALUE, list.get(0).intValue());       
    }
}

Erbauer (Builder Pattern)

Das Erbauermuster bietet sich immer dann an, falls Objekte mit sehr langen oder unterschiedlichen Parameterlisten erzeugt werden sollen. Der wesentliche Vorteil des Erbauers ist die flexible Konfigurierbarkeit eines Objektes bei seiner Instanziierung.

Erbauer Implementierung:

public class Builder {

    private final int intValue;
    private final String strValue;
           
    public Builder(InnerBuilder builder) {
       
        this.intValue = builder.intValue;
        this.strValue = builder.strValue;
    }

    public int getIntValue() {
       
        return intValue;
    }

    public String getStrValue() {
       
        return strValue;
    }
   
    static class InnerBuilder {
       
        private static final int BUILDER_DEFAULT_INT = 0;
        private static final String BUILDER_DEFAULT_STRING = "";
       
        private int intValue = BUILDER_DEFAULT_INT;       
        private String strValue = BUILDER_DEFAULT_STRING;
       
        public InnerBuilder intValue(final int intValueParam) {           
           
            this.intValue = intValueParam;           
            return(this);
        }
       
        public InnerBuilder strValue(final String strValueParam) {
           
            this.strValue = strValueParam;           
            return(this);
        }
       
        public Builder build() {
           
            return(new Builder(this));
        }
    }
}

JUnit-Test des Erbauers:

import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class TestBuilder {

    private static final int INT_TEST_VALUE = 25;
    private static final String STR_TEST_VALUE = "strValue";

    @Test
    public void testBuilderWithIntAndStringParameter() {
      
        final Builder builder = new Builder.InnerBuilder().
                                    intValue(25).strValue(STR_TEST_VALUE).build();
      
        assertEquals(INT_TEST_VALUE, builder.getIntValue());
        assertEquals(STR_TEST_VALUE, builder.getStrValue());
    }
   
    @Test
    public void testBuilderWithIntParameter() {
      
        final Builder builder = new Builder.InnerBuilder().intValue(25).build();
      
        assertEquals(25, builder.getIntValue());      
    }
   
    @Test
    public void testBuilderWithStringParameter() {
      
        final Builder builder = new Builder.InnerBuilder().strValue(STR_TEST_VALUE).build();
      
        assertEquals(STR_TEST_VALUE, builder.getStrValue());
    }
   
    @Test
    public void testBuilderWithNoParameter() {
      
        final Builder builder = new Builder.InnerBuilder().build();
      
        assertEquals(0, builder.getIntValue());  
        assertEquals("", builder.getStrValue());
    }
}


Der Rechtshinweis des Java Blog für Clean Code Developer ist bei der Verwendung und Weiterentwicklung des Quellcodes des Blogeintrages zu beachten.