Verbesserte Collection
Ähnlich wie im ersten Beispiel extrahieren wir eine eigene Methode für die Prüfung, ob ein bestimmtes Objekt bereits in der Collection ist. Wir packen also wieder das "Gefrickel" in eine eigene Methode weg:
<?php declare(strict_types=1);
namespace spriebsch\tfd\cleanCode\singleLevelOfAbstraction\refactoredCollection;
use RuntimeException;
final class SomeCollection
{
private array $items = [];
public function has(string $id): bool
{
return isset($this->items[$id]);
}
public function add(SomeObject $object): void
{
if ($this->has($object->id())) {
throw new RuntimeException(sprintf('Duplicate id %s', $object->id()));
}
$this->items[$object->id()] = $object;
}
}
Damit haben wir die Details der has()
-Prüfung aus der add()
-Methode entfernt.
Wir machen die has()
-Methode öffentlich, damit sie auch von außen verwendet werden kann.
Es ist ja auch schöner, erst mit has()
zu prüfen, ob ein Objekt schon in der Collection ist und dann auf den Aufruf von add()
zu verzichten, anstatt das add()
in einen try/catch
-Block einzuschliessen.
Ansonsten gilt auch hier, dass wir ein einfaches Refactoring durchgeführt haben und das nach außen wahrnehmbare Verhalten der Collection nicht verändert haben. Prüfen wir das nach:
example.php:10: class spriebsch\tfd\cleanCode\singleLevelOfAbstraction\refactoredCollection\SomeCollection#2 (1) { private array $items => array(1) { 'the-id' => class spriebsch\tfd\cleanCode\singleLevelOfAbstraction\refactoredCollection\SomeObject#3 (1) { private readonly string $id => string(6) "the-id" } } }
PHP Fatal error: Uncaught RuntimeException: Duplicate id the-id in SomeCollection.php:19 Stack trace: #0 example-will-fail.php(11): spriebsch\tfd\cleanCode\singleLevelOfAbstraction\refactoredCollection\SomeCollection->add() #1 {main} thrown in SomeCollection.php on line 19
Wir könnten in einem nächsten Schritt auch hier eine Guard Clause einführen.
Es gibt aber auch eine Asymmetrie in der add()
-Methode: bei der has()
-Prüfung sind wir von den Details und der Datenstruktur $items
abstrahiert, aber beim Speichern des Objektes arbeiten wir noch immer direkt auf der Datenstruktur.
Das ist eine klare Verletzung von Single Level of Abstraction!