Prüfungen abstrahieren
Wir abstrahieren die "Frickelei" in gesonderte Methoden, denen wir sprechende Namen geben. Beim Refactoring würden wir das Add Explaining Method nennen:
<?php declare(strict_types=1);
namespace spriebsch\tfd\cleanCode\singleLevelOfAbstraction\abstractedChecks;
use RuntimeException;
class SomeObject
{
private string $string;
public function __construct(string $string)
{
$this->ensureStringIsAtLeastFiveCharactersLong($string);
$this->ensureStringIsNoMoreThanTenCharactersLong($string);
$this->string = $string;
}
private function ensureStringIsAtLeastFiveCharactersLong(string $string): void
{
if (mb_strlen($string, 'UTF-8') <= 5) {
throw new RuntimeException('Too short');
}
}
private function ensureStringIsNoMoreThanTenCharactersLong(string $string)
{
if (mb_strlen($string, 'UTF-8') >= 10) {
throw new RuntimeException('Too long');
}
}
}
Die entstandenen Methoden sind sogenannte Guard Clauses. Wir sehen, dass ein Prinzip wie Single Level of Abstraction nicht im luftleeren Raum alleine steht, sondern durchaus im Kontext von Objektorientierung und Clean Code verwurzelt ist.
Wir könnten diesen Methoden beispielsweise auch einen Parameter geben, in dem wir die minimale beziehungsweise maximale Länge angeben. Jetzt wird das mit der Abstraktion noch etwas deutlicher, oder?
Da wir zwei einfache Refactorings vorgenommen haben, können wir unser Objekt noch genauso nutzen wie zuvor. Also probieren wir nochmal den zu kurzen String:
<?php declare(strict_types=1);
namespace spriebsch\tfd\cleanCode\singleLevelOfAbstraction\abstractedChecks;
require __DIR__ . '/autoload.php';
$object = new SomeObject('short');
var_dump($object);
PHP Fatal error: Uncaught RuntimeException: Too short in SomeObject.php:22 Stack trace: #0 SomeObject.php(13): spriebsch\tfd\cleanCode\singleLevelOfAbstraction\abstractedChecks\SomeObject->ensureStringIsAtLeastFiveCharactersLong() #1 short-will-fail.php(7): spriebsch\tfd\cleanCode\singleLevelOfAbstraction\abstractedChecks\SomeObject->__construct() #2 {main} thrown in SomeObject.php on line 22
Wie erwartet (noch immer) eine Exception. Auch der zu lange String ...
<?php declare(strict_types=1);
namespace spriebsch\tfd\cleanCode\singleLevelOfAbstraction\abstractedChecks;
require __DIR__ . '/autoload.php';
$object = new SomeObject('this is far too long');
var_dump($object);
PHP Fatal error: Uncaught RuntimeException: Too long in SomeObject.php:29 Stack trace: #0 SomeObject.php(14): spriebsch\tfd\cleanCode\singleLevelOfAbstraction\abstractedChecks\SomeObject->ensureStringIsNoMoreThanTenCharactersLong() #1 long-will-fail.php(7): spriebsch\tfd\cleanCode\singleLevelOfAbstraction\abstractedChecks\SomeObject->__construct() #2 {main} thrown in SomeObject.php on line 29
... führt noch immer zu einer Exception. Also versuchen wir nochmal den Happy Path:
<?php declare(strict_types=1);
namespace spriebsch\tfd\cleanCode\singleLevelOfAbstraction\abstractedChecks;
require __DIR__ . '/autoload.php';
$object = new SomeObject('a-string');
var_dump($object);
example.php:8: class spriebsch\tfd\cleanCode\singleLevelOfAbstraction\abstractedChecks\SomeObject#2 (1) { private string $string => string(8) "a-string" }
Das Ergebnis ist unverändert. Gut so. Wir haben jetzt einen viel besser lesbaren Konstruktor, der uns Details erspart wie zum Beispiel die Frage, in welchem Encoding der zu prüfende String vorliegt. Das ist Abstraktion.
Sehen wir uns noch ein anderes Beispiel an.