• Как провести соответствие между строкой и классом с точки зрения SOLID?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Это всё очень плохо.
    В первом варианте человек должен знать, как мяукают кошки, а в последнем "правильном" варианте человек трогает не кошку, а кошачий голос(?!).
    В "идеальном" варианте опять же выбирается не животное, которое надо погладить, а его голос.

    Чтобы следовать принципам солид, надо понять в первую очередь ЗАЧЕМ это всё делается.
    А делается это для того чтобы уменьшить связность. Чтобы класс, использующий какой-либо функционал, не знал деталей его реализации. И, соответственно, мы могли бы менять реализацию без опасения поломать что-то в классе-пользователе.

    При этом extends, кроме как от абстрактного класса, эту связность всегда увеличивает.
    И его надо избегать. А использовать принцип Composition over inheritance. То есть нужный функционал получать не наследованием, а передачей независимых функциональных модулей в виде параметров.

    Соответственно, нам надо сделать иерархию: голос - животное - потрогать.
    И вот теперь у нас хоть голос, хоть животное, будут открыты для каких угодно изменений, до тех пор пока они поддерживают публичный контракт.
    / ******* голоса *******/
    abstract class VoiceEngine {
    	public function getVoice() {}
    }
    class CatVoiceEngine extends VoiceEngine {
    	public function getVoice() {
    		return "Meow!";
    	}
    }
    class DogVoiceEngine extends VoiceEngine {
    	public function getVoice() {
    		return "Bark!";
    	}
    }
    class HumanVoiceEngine extends VoiceEngine {
    	public function getVoice() {
    		return "Да пошёл ты!";
    	}
    }
    / ******* животные *******/
    abstract class Animal {
    	public function __construct(public VoiceEngine $voiceEngine) {}
    	public function say() {
    		echo $this->voiceEngine->getVoice();
    	}
    }
    class Cat extends Animal{}
    class Dog extends Animal{}
    class Human extends Animal{
    	public function touchAnimal(Animal $animal) {
    		$animal->say();
    	}
    }
    / ******* исполнение *******/
    $cat = new Cat(new CatVoiceEngine());
    $dog = new Dog(new DogVoiceEngine());
    $human = new Human(new HumanVoiceEngine());
    $human->touchAnimal($cat);
    $human->touchAnimal($dog);
    $human->touchAnimal($human);


    После того как я, раздуваясь от гордости, написал этот ответ, до меня вдруг дошло что на вопрос-то я так и не ответил.
    Соответственно, задачу выбора животного возлагаем на отдельную сущность:

    class AnimalFactory {
        public static function create($type) {
            return match($type) {
                'cat' => new Cat(new CatVoiceEngine()),
                'dog' => new Dog(new DogVoiceEngine()),
                'human' => new Human(new HumanVoiceEngine()),
            };
        }
    }
    $human = new Human(new HumanVoiceEngine());
    $human->touchAnimal(AnimalFactory::create('cat'));

    В итоге мы вернулись к тому же кейсу (match - это улучшенный case), но при этом у нас всё разделено, и каждый класс занимается строго своим делом.
    Ответ написан
  • Работа с существующими клиентами Upwork: как настроить работу напрямую?

    an-tar
    @an-tar
    Full stack web developer
    1. Инвойс по форме и оплата напрямую через swift в неподсанкционные банки
    2. Разные софтины есть, на вкус и цвет - toggl, teamlogger, tahometer и т.д.
    3. На доверии, если старый проверенный клиент - тут нет проблем. Или иначе договаривайтесь.
    4. У них есть официальная программа - "заплати процент и уводи клиента", не помню точное название, погуглите. Если Upwork узнает (или кто "стукнет",например, сам клиент, такое бывало у других), о том, что вы общаетесь вне платформы..санкции могут быть вплоть до бана. Это если до заключения контракта. А если после - вы в общем-то вольны общаться и вне платформы. Только вот с учетом невозможности заключать новые контракты и быть в результатах поиска имхо толку от платформы мало.
    Ответ написан
    6 комментариев