Der vollständige Konstruktor

oop clean code constructor

Vor einigen Tagen habe ich in einem Artikel beschrieben, wie man mit vielen Parametern in Methoden umgehen kann. Beim Konstruktor handelt es sich allerdings um einen Sonderfall, denn im Gegensatz zu normalen Methoden haben die einzelnen Parameter oft nicht viel miteinander zu tun und lassen sich deswegen nicht zu Parameterobjekten zusammenfassen. Um den Code dennoch lesbar zu halten, benötigen wir andere Mittel.

Die Lösung für das Problem ist ein Creator mit einem Fluent Interface. Schauen wir uns ein Beispiel an.

class Address
{
    public function __construct($street, $houseNumber, $postalCode, $city, $country)
    {
        $this->_street      = $street;
        $this->_houseNumber = $houseNumber;
        $this->_postalCode  = $postalCode;
        $this->_city        = $city;
        $this->_country     = $country;
    }

    //...

    public static function describeWith()
    {
        return new AddressCreator();
    }
}

class AddressCreator
{
    private $_street;
    private $_houseNumber;
    private $_postalCode;
    private $_city;
    private $_country;

    public function withStreet($value)
    {
        $this->_street = $value;
        return $this;
    }

    public function withHouseNumber($value)
    {
        $this->_houseNumber = $value;
        return $this;
    }

    public function withPostalCode($value)
    {
        $this->_postalCode = $value;
        return $this;
    }

    public function withCity($value)
    {
        $this->_city = $value;
        return $this;
    }

    public function withCountry($value)
    {
        $this->_country = $value;
        return $this;
    }

    public function andCreate()
    {
        foreach ($this AS $property => $value) {
            if ($value === null) {
                throw new Exception("Property $property is null.");
            }
        }
        return new Address(
            $this->_street,
            $this->_houseNumber, 
            $this->_postalCode,
            $this->_city,
            $this->_country
        );
    }
}

Die Erstellen neuer Objekte liest sich nun fast wie ein normaler Satz.

$address = Address::describe()
               ->withStreet('Universitätsstraße')
               ->withHouseNumber('150')
               ->withPostalCode('44801')
               ->withCity('Bochum')
               ->andCreate();

Wer zudem sicher gehen möchte, dass jeder Programmierer den Creator nutzt, dem mag folgende Variante besser gefallen.

class Address
{
    public function __construct(AddressCreator $creator)
    {
        $this->_street      = $creator->getStreet();
        $this->_houseNumber = $creator->getHouseNumber();
        $this->_postalCode  = $creator->getPostalCode();
        $this->_city        = $creator->getCity();
        $this->_country     = $creator->getCountry();
    }

    //...

    public static function describeWith()
    {
        return new AddressCreator();
    }
}

class AddressCreator
{
    private $_street;
    private $_houseNumber;
    private $_postalCode;
    private $_city;
    private $_country;

    public function withStreet($value)
    {
        $this->_street = $value;
        return $this;
    }

    //...

    public function andCreate()
    {
        foreach ($this AS $property => $value) {
            if ($value === null) {
                throw new Exception("Property $property is null.");
            }
        }
        return new Address($this);
    }

    public function getStreet()
    {
        return $this->_street;
    }

    public function getHouseNumber()
    {
        return $this->_houseNumber;
    }

    public function getPostalCode()
    {
        return $this->_postalCode;
    }

    public function getCity()
    {
        return $this->_city;
    }

    public function getCountry()
    {
        return $this->_country;
    }
}

So schön die erhöhte Lesbarkeit auch ist, sie bringt auch einige Nachteilemit.

  • Man benötigt eine zusätzliche Klasse, es besteht also ein erhöhter Implementierungsaufwand.
  • Der Creator benötigt einige Eigenschaften, die die Klasse selbst ebenfalls benötigt. Diese enge Kopplung erschwert spätere Änderungen.

Ob die Nachteile die verbesserte Lesbarkeit des Codes aufwiegen, muss jeder selbst entscheiden. 😉

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *