===== Состояние (State) ===== [[http://webmastermsk.ru:30000/serg/patterns-php/-/blob/main/behavioral/State.php|▶ code]] Состояние - инкапсулирует изменение поведения одних и тех же методов в зависимости от состояния объекта. Этот паттерн поможет изящным способом изменить поведение объекта во время выполнения не прибегая к большим монолитным условным операторам. Использование шаблона "Состояние" локализует зависящее от состояния поведение и делит его на части, соответствующие состояниям, переходы между состояниями становятся явными, а процесс работы с объектом – более прозрачным и понятным. **Использование:** * Когда у вас есть объект, поведение которого кардинально меняется в зависимости от внутреннего состояния, причём типов состояний много, и их код часто меняется. * Когда код класса содержит множество больших, похожих друг на друга, условных операторов, которые выбирают поведения в зависимости от текущих значений полей класса. * Когда вы сознательно используете табличную машину состояний, построенную на условных операторах, но вынуждены мириться с дублированием кода для похожих состояний и переходов. **Преимущества:** * Избавляет от множества больших условных операторов машины состояний. * Концентрирует в одном месте код, связанный с определённым состоянием. * Упрощает код контекста. **Недостатки:** * Может неоправданно усложнить код, если состояний мало и они редко меняются. **Связи с другими паттернами** * Мост, Стратегия и Состояние (а также слегка и Адаптер) имеют схожие структуры классов – все они построены на принципе «композиции», то есть делегирования работы другим объектам. Тем не менее, они отличаются тем, что решают разные проблемы. Помните, что паттерны – это не только рецепт построения кода определённым образом, но и описание проблем, которые привели к данному решению. * Состояние можно рассматривать как надстройку над Стратегией. Оба паттерна используют композицию, чтобы менять поведение основного объекта, делегируя работу вложенным объектам-помощникам. Однако в Стратегии эти объекты не знают друг о друге и никак не связаны. В Состоянии сами конкретные состояния могут переключать контекст. **State.php** state; } public function setState(State $state): void { $this->state = $state; } public static function make(): Task { $self = new self(); $self->setState(new Created()); return $self; } public function proceedToNext(): void { $this->state->toNext($this); } public function toString() { return $this->state->getStatus(); } } class Created implements State { public function toNext(Task $task) { $task->setState(new Process()); } public function getStatus(): string { return 'Created'; } } class Process implements State { public function toNext(Task $task) { $task->setState(new Test()); } public function getStatus(): string { return 'Process'; } } class Test implements State { public function toNext(Task $task) { $task->setState(new Done()); } public function getStatus(): string { return 'Test'; } } class Done implements State { public function toNext(Task $task) { } public function getStatus(): string { return 'Done'; } } $task = Task::make(); $task->proceedToNext(); $task->proceedToNext(); //echo $task->getState()->getStatus(); // Test echo $task->toString(); // Test // ----------- 2 ----------- interface WritingState { public function write(string $words); } class UpperCase implements WritingState { public function write(string $words) { echo strtoupper($words); } } class LowerCase implements WritingState { public function write(string $words) { echo strtolower($words); } } class Defaulted implements WritingState { public function write(string $words) { echo $words; } } class TextEditor { protected $state; public function __construct(WritingState $state) { $this->state = $state; } public function setState(WritingState $state) { $this->state = $state; } public function type(string $words) { $this->state->write($words); } } $editor = new TextEditor(new Defaulted()); $editor->type('First line'); $editor->setState(new UpperCase()); $editor->type('Second line'); $editor->type('Third line'); $editor->setState(new LowerCase()); $editor->type('Fourth line'); $editor->type('Fifth line'); // Output: // First line // SECOND LINE // THIRD LINE // fourth line // fifth line