Primitive Obsession code smell

Има случаи, в които е по-добре да използваме обекти вместо примитивни типове. Нека погледнем следният пример:

Имаме клас User в който подаваме дадено пропърти, например $url като стринг и също, преди да го сетнем, правим някаква примерна валидация.

class User
{
    private string $url;

    public function setUserUrl(string $url) : void
    {
        if (false === filter_var($url, FILTER_VALIDATE_URL)) {
            throw new SomeValidationException('Wrong url bla bla bla...');
        }
        $this->url = $url;
    }

    public function getUserUrl() : string
    {
        return $this->url;
    }

    // ...
}

На пръв поглед всичко е доста просто.

Но първото, което не е ОК, е че валидацията на URL-a e в класа User. Не нарушаваме ли Sigle Responsibility SOLID принципът?

Също, ако трябва да подадем URL и на друг клас, там също трябва да я има тази валидация – повтаряне на код.

Да не говорим, че ако подаваме така, по отделно, може да имаме „експлозия от входни параметри“ ако се наложи да подаваме и други стойности.

Няма ли да е по-елегантно и гъвкаво ако създадем нов клас Url и там да изнесем валидирането и евентуално друга логика, свързана с Url-и. И където ни трябва, просто да инджектваме обект от класа Url?
T.н. „Replace Data Value with Object “ техника за рефакториране.

class User
{
    private string $url;

    public function setUserUrl(Url $url) : void
    {
        $this->url = $url;
    }

    public function getUserUrl() : string
    {
        return $this->url->getUrlAddress();
    }

    // ...
}

class Url
{
    private string $url;

    public function __construct(string $url)
    {
        if (false === filter_var($url, FILTER_VALIDATE_URL)) {
            throw new SomeValidationException('Wrong url bla bla bla...');
        }
        $this->url = $url;
    }

    public function getUrlAddress() : string
    {
        return $this->url;
    }

    // ...
}

Вижда се, че Primitive Obsession трябва да се избягва, когато не просто използваме примитивни типове за някаква стойност, но трябва и да имаме някаква логика, на която тези примитивни стойности да се подчиняват.

Добър пример би бил ако например искаме да имаме пропърти $age за даден User, но също и трябва да я използваме тази възраст само за живи хора, а не и за например исторически личности, за които възрастта може да е стотици години.
Тогава не може просто да подаваме произволен, положителен integer.

Литература:

https://dzone.com/articles/code-quality-fighting-primitive-obsession-code-sme-1