Выбор шаблона "Состояние" вместо наследования
От: zfima  
Дата: 04.11.13 13:49
Оценка:
Здравствуйте

Осваиваю книгу Рефакторинг Мартина Фулера.

В одном месте заменяет switch. вместо наследования использует шаблон "Состояние":
"... Такой прием позволяет заменить оператор switch полиморфизмом. К сожалению, у этого решения есть маленький недостаток – оно не работает. Фильм за время своего существования может изменить тип,
объект же, пока он жив, изменить свой класс не может. Однако выход есть – паттерн «Состояние» (State pattern [Gang of Four])" стр52.

Может мне кто то объяснить, зачем?

Почему надо изменять свой класс?

    public abstract class Movie
    {
        public abstract double GetCharge(int daysRented);
    }

    public class CHILDRENSMovie : Movie
    {
        public override double GetCharge(int daysRented)
        {
            throw new NotImplementedException();
        }
    }

    public class REGULARMovie : Movie
    {
        public override double GetCharge(int daysRented)
        {
            throw new NotImplementedException();
        }
    }


Почему вышеуказанная иерархия "не подходит"?


Спасибо
Re: Выбор шаблона "Состояние" вместо наследования
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 04.11.13 14:02
Оценка: 3 (1) +2
Здравствуйте, zfima, Вы писали:

Z>Здравствуйте


Z>Осваиваю книгу Рефакторинг Мартина Фулера.


Z>В одном месте заменяет switch. вместо наследования использует шаблон "Состояние":

Z>"... Такой прием позволяет заменить оператор switch полиморфизмом. К сожалению, у этого решения есть маленький недостаток – оно не работает. Фильм за время своего существования может изменить тип,
Z>объект же, пока он жив, изменить свой класс не может. Однако выход есть – паттерн «Состояние» (State pattern [Gang of Four])" стр52.


Z>Почему надо изменять свой класс?


В твоем примере с Movie вполне может оказаться, что тип кина поменяется с Regular на Children, что твоя объектная модель не выдержит.

А вообще state нужен для моделирования объектов со встроенным поведением. Например монстры в игре вполне могут по разному вести себя в зависимости от уровня здоровья. Чтобы не делать россыпи if и switch в методах можно воспользоваться паттерном state.
Re[2]: Выбор шаблона "Состояние" вместо наследования
От: zfima  
Дата: 04.11.13 14:22
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, zfima, Вы писали:


Z>>Здравствуйте


Z>>Осваиваю книгу Рефакторинг Мартина Фулера.


Z>>В одном месте заменяет switch. вместо наследования использует шаблон "Состояние":

Z>>"... Такой прием позволяет заменить оператор switch полиморфизмом. К сожалению, у этого решения есть маленький недостаток – оно не работает. Фильм за время своего существования может изменить тип,
Z>>объект же, пока он жив, изменить свой класс не может. Однако выход есть – паттерн «Состояние» (State pattern [Gang of Four])" стр52.


Z>>Почему надо изменять свой класс?


G>В твоем примере с Movie вполне может оказаться, что тип кина поменяется с Regular на Children, что твоя объектная модель не выдержит.


G>А вообще state нужен для моделирования объектов со встроенным поведением. Например монстры в игре вполне могут по разному вести себя в зависимости от уровня здоровья. Чтобы не делать россыпи if и switch в методах можно воспользоваться паттерном state.


Спасибо за объяснение!
Re[2]: Выбор шаблона "Состояние" вместо наследования
От: zfima  
Дата: 04.11.13 15:02
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, zfima, Вы писали:


Z>>Здравствуйте


Z>>Осваиваю книгу Рефакторинг Мартина Фулера.


Z>>В одном месте заменяет switch. вместо наследования использует шаблон "Состояние":

Z>>"... Такой прием позволяет заменить оператор switch полиморфизмом. К сожалению, у этого решения есть маленький недостаток – оно не работает. Фильм за время своего существования может изменить тип,
Z>>объект же, пока он жив, изменить свой класс не может. Однако выход есть – паттерн «Состояние» (State pattern [Gang of Four])" стр52.


Z>>Почему надо изменять свой класс?


G>В твоем примере с Movie вполне может оказаться, что тип кина поменяется с Regular на Children, что твоя объектная модель не выдержит.


G>А вообще state нужен для моделирования объектов со встроенным поведением. Например монстры в игре вполне могут по разному вести себя в зависимости от уровня здоровья. Чтобы не делать россыпи if и switch в методах можно воспользоваться паттерном state.


После имплементации Состояния, сложилось впечатление, что шаблон состояние = Dependency Injection + делегирование поведения другому классу

Это так?
Re[3]: Выбор шаблона "Состояние" вместо наследования
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 04.11.13 15:17
Оценка:
Здравствуйте, zfima, Вы писали:

Z>Здравствуйте, gandjustas, Вы писали:


G>>Здравствуйте, zfima, Вы писали:


Z>>>Здравствуйте


Z>>>Осваиваю книгу Рефакторинг Мартина Фулера.


Z>>>В одном месте заменяет switch. вместо наследования использует шаблон "Состояние":

Z>>>"... Такой прием позволяет заменить оператор switch полиморфизмом. К сожалению, у этого решения есть маленький недостаток – оно не работает. Фильм за время своего существования может изменить тип,
Z>>>объект же, пока он жив, изменить свой класс не может. Однако выход есть – паттерн «Состояние» (State pattern [Gang of Four])" стр52.


Z>>>Почему надо изменять свой класс?


G>>В твоем примере с Movie вполне может оказаться, что тип кина поменяется с Regular на Children, что твоя объектная модель не выдержит.


G>>А вообще state нужен для моделирования объектов со встроенным поведением. Например монстры в игре вполне могут по разному вести себя в зависимости от уровня здоровья. Чтобы не делать россыпи if и switch в методах можно воспользоваться паттерном state.


Z>После имплементации Состояния, сложилось впечатление, что шаблон состояние = Dependency Injection + делегирование поведения другому классу

Z>Это так?
Может и так, это уже вопрос терминологии.

Вообще паттерн state говорит о том, что поведение надо вынести в класс state, хотя этот класс состояния таки не содержит. Я бы назвал этот паттерн "external behavior" и объединил бы со стратегией.
Re[3]: Выбор шаблона "Состояние" вместо наследования
От: landerhigh Пират  
Дата: 05.11.13 00:21
Оценка: 3 (1) +1
Здравствуйте, zfima, Вы писали:


Z>После имплементации Состояния, сложилось впечатление, что шаблон состояние = Dependency Injection + делегирование поведения другому классу


Z>Это так?


Нет. точнее, не совсем так.

Шаблон State есть ни что иное, как вариант реализации КА (FSM), причем выигрыш от его внедрения заметен только в случаях, когда поведение многих честей системы очень сильно меняется в зависимости от состояния.
www.blinnov.com
Re[3]: Выбор шаблона "Состояние" вместо наследования
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 05.11.13 07:57
Оценка:
Здравствуйте, zfima, Вы писали:

G>>А вообще state нужен для моделирования объектов со встроенным поведением. Например монстры в игре вполне могут по разному вести себя в зависимости от уровня здоровья. Чтобы не делать россыпи if и switch в методах можно воспользоваться паттерном state.


Z>После имплементации Состояния, сложилось впечатление, что шаблон состояние = Dependency Injection + делегирование поведения другому классу


Z>Это так?


Dependency injection здесь ни при чем. Делегируется только поведение, а основной класс управляет переключением состояния.
Re[2]: Выбор шаблона "Состояние" вместо наследования
От: zfima  
Дата: 05.11.13 10:57
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, zfima, Вы писали:


Z>>Здравствуйте


Z>>Осваиваю книгу Рефакторинг Мартина Фулера.


Z>>В одном месте заменяет switch. вместо наследования использует шаблон "Состояние":

Z>>"... Такой прием позволяет заменить оператор switch полиморфизмом. К сожалению, у этого решения есть маленький недостаток – оно не работает. Фильм за время своего существования может изменить тип,
Z>>объект же, пока он жив, изменить свой класс не может. Однако выход есть – паттерн «Состояние» (State pattern [Gang of Four])" стр52.


Z>>Почему надо изменять свой класс?


G>В твоем примере с Movie вполне может оказаться, что тип кина поменяется с Regular на Children, что твоя объектная модель не выдержит.


G>А вообще state нужен для моделирования объектов со встроенным поведением. Например монстры в игре вполне могут по разному вести себя в зависимости от уровня здоровья. Чтобы не делать россыпи if и switch в методах можно воспользоваться паттерном state.


Я правильно понял монстрологию?


public class Monster
{
    public IMonsterState MonsterState { set; get; }

    public Monster(IMonsterState initMonsterState)
    {
        MonsterState = initMonsterState;
    }

    public void HealthImprove()
    {
        MonsterState.HealthImprove(this);
    }

    public void HealthDeteriorate()
    {
        MonsterState.HealthDeteriorate(this);
    }

    public string ReportStrength()
    {
        return MonsterState.ReportStrength();
    }
}

public interface IMonsterState
{
    void HealthImprove(Monster monster);
    void HealthDeteriorate(Monster monster);
    string ReportStrength();
}

public class VeryStrongMonsterState : IMonsterState
{
    public void HealthImprove(Monster monster)
    {
        //can not improve health
    }

    public void HealthDeteriorate(Monster monster)
    {
        monster.MonsterState = new StrongMonsterState();
    }

    public string ReportStrength()
    {
        return "Very Strong Monster";
    }
}

public class StrongMonsterState : IMonsterState
{
    public void HealthImprove(Monster monster)
    {
        monster.MonsterState = new VeryStrongMonsterState();
    }

    public void HealthDeteriorate(Monster monster)
    {
        monster.MonsterState = new WeakMonsterState();
    }

    public string ReportStrength()
    {
        return "Strong Monster";
    }
}

public class WeakMonsterState : IMonsterState
{
    public void HealthImprove(Monster monster)
    {
        monster.MonsterState = new StrongMonsterState();
    }

    public void HealthDeteriorate(Monster monster)
    {
        //can not go down
    }

    public string ReportStrength()
    {
        return "Weak Monster";
    }
}


Использование:


[TestMethod]
public void TestMethod1()
{
    Monster monster = new Monster(new VeryStrongMonsterState());

    monster.HealthImprove();
    Assert.AreEqual(monster.ReportStrength(), "Very Strong Monster");
    monster.HealthImprove();
    Assert.AreEqual(monster.ReportStrength(), "Very Strong Monster");
    monster.HealthImprove();
    Assert.AreEqual(monster.ReportStrength(), "Very Strong Monster");

    monster.HealthDeteriorate();
    Assert.AreEqual(monster.ReportStrength(), "Strong Monster");
    monster.HealthDeteriorate();
    Assert.AreEqual(monster.ReportStrength(), "Weak Monster");
    monster.HealthDeteriorate();
    Assert.AreEqual(monster.ReportStrength(), "Weak Monster");
}
Re[3]: Выбор шаблона "Состояние" вместо наследования
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 05.11.13 17:55
Оценка:
Здравствуйте, zfima, Вы писали:

Z>Здравствуйте, gandjustas, Вы писали:


G>>Здравствуйте, zfima, Вы писали:


Z>>>Здравствуйте


Z>>>Осваиваю книгу Рефакторинг Мартина Фулера.


Z>>>В одном месте заменяет switch. вместо наследования использует шаблон "Состояние":

Z>>>"... Такой прием позволяет заменить оператор switch полиморфизмом. К сожалению, у этого решения есть маленький недостаток – оно не работает. Фильм за время своего существования может изменить тип,
Z>>>объект же, пока он жив, изменить свой класс не может. Однако выход есть – паттерн «Состояние» (State pattern [Gang of Four])" стр52.


Z>>>Почему надо изменять свой класс?


G>>В твоем примере с Movie вполне может оказаться, что тип кина поменяется с Regular на Children, что твоя объектная модель не выдержит.


G>>А вообще state нужен для моделирования объектов со встроенным поведением. Например монстры в игре вполне могут по разному вести себя в зависимости от уровня здоровья. Чтобы не делать россыпи if и switch в методах можно воспользоваться паттерном state.


Z>Я правильно понял монстрологию?


Да, только обычно все пляски с состояниями скрыты от внешних глаз. Когда потребитель класса определяет его поведение через класс поведения это становится стратегией.
Re[4]: Выбор шаблона "Состояние" вместо наследования
От: zfima  
Дата: 06.11.13 07:28
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, zfima, Вы писали:


Z>>Здравствуйте, gandjustas, Вы писали:


G>>>Здравствуйте, zfima, Вы писали:


Z>>>>Здравствуйте


Z>>>>Осваиваю книгу Рефакторинг Мартина Фулера.


Z>>>>В одном месте заменяет switch. вместо наследования использует шаблон "Состояние":

Z>>>>"... Такой прием позволяет заменить оператор switch полиморфизмом. К сожалению, у этого решения есть маленький недостаток – оно не работает. Фильм за время своего существования может изменить тип,
Z>>>>объект же, пока он жив, изменить свой класс не может. Однако выход есть – паттерн «Состояние» (State pattern [Gang of Four])" стр52.


Z>>>>Почему надо изменять свой класс?


G>>>В твоем примере с Movie вполне может оказаться, что тип кина поменяется с Regular на Children, что твоя объектная модель не выдержит.


G>>>А вообще state нужен для моделирования объектов со встроенным поведением. Например монстры в игре вполне могут по разному вести себя в зависимости от уровня здоровья. Чтобы не делать россыпи if и switch в методах можно воспользоваться паттерном state.


Z>>Я правильно понял монстрологию?


G>Да, только обычно все пляски с состояниями скрыты от внешних глаз. Когда потребитель класса определяет его поведение через класс поведения это становится стратегией.


Пляска подразумевает передачу в конструктор класса Monster параметра IMonsterState ?

И, насколько мне позволяют судить мои скудные познания в области шаблонов, различий между стратегией и состоянием больше, чем передачу начального состояния в конструктор:

в стратегии классы, имплементирующие алгоритмы, ничего не знают об их caller, а в состоянии они о нем знают и изменяют его
в стратегии классы, имплементирующие алгоритмы, не заменяют своими "родственниками" никого и ничего, а в состоянии они этим и живут. Как кукушка.
Re[4]: Выбор шаблона "Состояние" вместо наследования
От: Кодт Россия  
Дата: 06.11.13 08:07
Оценка: 1 (1)
Здравствуйте, gandjustas, Вы писали:

G>Вообще паттерн state говорит о том, что поведение надо вынести в класс state, хотя этот класс состояния таки не содержит. Я бы назвал этот паттерн "external behavior" и объединил бы со стратегией.


Стратегия — это линия поведения, которая не будет меняться по ходу пьесы. А состояние будет.
Объект стратегии неизменный и разделяемый, объект состояния может быть сам по себе переменным.
Так что валить в кучу, пожалуй, не стоит.
Перекуём баги на фичи!
Re[5]: Выбор шаблона "Состояние" вместо наследования
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 06.11.13 11:26
Оценка:
Здравствуйте, zfima, Вы писали:

Z>И, насколько мне позволяют судить мои скудные познания в области шаблонов, различий между стратегией и состоянием больше, чем передачу начального состояния в конструктор:


Z>в стратегии классы, имплементирующие алгоритмы, ничего не знают об их caller, а в состоянии они о нем знают и изменяют его

Z>в стратегии классы, имплементирующие алгоритмы, не заменяют своими "родственниками" никого и ничего, а в состоянии они этим и живут. Как кукушка.

Это все теория. С точки зрения кода разница будет очень простая:
1) Стратегия передается классу вызывающим.
2) Состояние изменяется самим классом и скрыто от потребителя.

Сами классы стратегии и состояния почти не отличаются.
Re: Выбор шаблона "Состояние" вместо наследования
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.11.13 20:07
Оценка:
Здравствуйте, zfima, Вы писали:

Z>Здравствуйте


Z>Осваиваю книгу Рефакторинг Мартина Фулера.


Это вобщем бесполезная книга сама по себе. Что бы от нее был толк, нужно паралельно смотреть GoF, а примеры рефакторинга в книге Джошуа Кериевски "Рефакторинг с использованием паттернов проектирования", до кучи можно добавить Майкла Физерса "Legacy Code" где он показывает все то же, только под другим углом и с упором на древний код. И еще неплохо посмотреть примеры рефакторинга у Кента Бека "XP:TDD"

Кстати говоря, Кериевски в своей книге очень хорошо показывает применение паттерна State
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.