2016-01-31 1 views
2

Извините за давние примеры, но недавно я столкнулся с проблемой такого типа программного обеспечения и думал об этом. Не уверен, есть ли для этого термин, поэтому я дам два общих примера, чтобы дать представление:Какие шаблоны проектирования могут помочь моделировать объекты, поведение которых меняется динамически или объекты со многими необязательными поведением?

Пример 1: Вы работаете над игрой RPG, и у вас есть класс для главного героя. Реакция этого персонажа на игровой мир меняется в зависимости от того, на что вы надеваете/держите, выделенные навыки, в основном внутреннее состояние вашего объекта.

Скажет у вас есть следующие пункты в игре:

  • Кольца регенерации: позволяешь вашему персонажу восстанавливать здоровье с течением времени
  • подлых кроссовок: увеличение прокрасться
  • Волшебного зеркала: отражает% поступающий повреждение
  • Doofy очки: основные крафта ресурсы

Пример 2: У вас есть Toyota Corolla. Есть разные конфигурации, но все они Toyota Corollas. ABS и Traction Control являются дополнительными функциями (поведением), которые вы можете добавить к базовой модели.

  • Базовая модель ничего не делает при запуске.
  • с ABS, проверки автомобиля и реагирует на внезапные остановки, когда автомобиль бежит
  • С контроля тяги, проверки автомобиля и реагирует на потерю тяги, когда автомобиль бежит
  • И, очевидно, когда у вас есть автомобиль с оба, вы будете делать оба поведения, когда машина работает.

Общие свойства двух примеров:

  • класс значение имеет конкретный чистый лист, что он может начать с
  • дополнительные элементы/части могут добавить способность или дополнительное поведение к этому объекту; что-то дополнительно, чтобы сделать в игру клещ/во время работы
  • может или не может мутировать объект, когда элемент/поведение добавляется или снимается из него (инкремента предварительного просмотра фильма, когда надевая кроссовки, уменьшить его, принимая его)

Потенциальные решения (но не адекватные):

если заявления:

if ch.isWearing 'doofy glasses': 
    render with doofy shader 
else if ch.isWearing ... 

не работает. Необходимо добавить предложение для каждой части. Класс может стать большим и сложным очень быстро.

модель

Стратегии:

class TractionControlStrategy 
class ABSstrategy 

class Toyota: 
    TractionControlStrategy tcs 
    ABSstrategy abs 
    run(): 
     if tcs not null: 
      tcs.run() 
     if abs not null: 
      abs.run() 

carWithTCS = new Toyota(new TractionControlStrategy()) 

Не намного лучше, чем предыдущее решение, как вы до сих пор длинный список если заявления

Стратегия с подклассами:

class Toyota: 
    run(): 
     // does nothing 

class ToyotaWithABS : Toyota 
    ABSstrategy abs = new ABSstrategy() 
    run(): 
     abs.run 

class ToyotaWithTCS : Toyota ... 

удовлетворяющего Открытым/Закрытый принцип, я думаю. Лучше, чем предыдущий? Но теперь вам нужно создать класс для каждой комбинации конфигураций. Если позже вы узнаете, что есть другие дополнительные функции, количество классов будет удвоено для каждой функции, которую вам нужно реализовать ...

Как можно моделировать эти типы взаимодействий и поведения с помощью ООП? Какие шаблоны дизайна или комбинации шаблонов дизайна способствуют этому?

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

Я изучаю OpenGL, работая над своим 3D-сеткой/модельным классом. Этот вопрос связан с тем, что в моем рендерере индексирование и текстуры являются необязательными для сетки. Таким образом, сетка может быть только вершинами, индексированными вершинами, вершинами и текстурами или всеми 3. Кроме того, я не могу предвидеть, какие функции я могу добавить в будущем, поскольку я не знаю, что я буду изучать, как месяц вниз по линии, поэтому мне нужен класс, чтобы быть гибким и расширяемым.

ответ

1

Вы правы, и любой вариант, где вам нужно описать все возможные комбинации (будь то через коммутатор/если или через иерархию классов), не очень хорошо.

Один из способов - использовать decoratorpattern, чтобы обернуть ваш основной класс и добавить динамические свойства. Или вы можете разделить класс Stats как поданный в основном классе и украсить его дополнительными предметами.

class Thing 

    BasicStats stats 

    constructor() 
     this->stats = new BasicStats() 

    addItem(Item item) 
     // Decorate current stats with new stats 
     item->setComponent(this->stats) 
     this->stats = item 
     return this 

    int getHealth() 
     return this->stats->getHealth() 

Вы можете использовать его как это:

thing = new Thing() // has basic stats 
thing->addItem(new MagicMirror)->addItem(new SilverBullet) 
// will go through the chain of decorators to get the value 
health = thing->getHealth() 

Другой способ иметь список динамических опций (или элементов) в главном классе:

class Thing 

    Stats stats 
    ItemList items 

    updateStats() 
     for item in this->items 
      item->updateStats(this->stats) 
      // OR if we want to not disclose the stats to items 
      // we can pass this and items should use 
      // character's methods to change stats 
      item->updateStats(this) 

    add(Item item) 
     this->items->append(item) 
     return this 

, которые могут быть используется следующим образом:

thing = new Thing() 
thing->add(new MagicMirror())->add(new RingOfRegeneration)->updateStats() 

Memento также может быть полезен, если вы не хотите напрямую изменять статистику персонажа. Например, если у вас есть функция «сравнения», когда пользователь (или игрок) может комбинировать разные наборы элементов, чтобы увидеть влияние, а затем «применить» их.

Также посмотрите на chain-of-responsibility, аналогичный опции со списком характеристик - вы можете создать цепочку «Предметы» и запросить стат из этой цепочки. Как вы можете начать с передачи базового значения здоровья, которое затем будет преобразовано каждым элементом, и вы получите «обновленное» значение в конце цепочки.

Update: еще одна идея, visitor может быть полезно также:

# Base class for stats, Element 
class Stat 

    abstract accept(StatVisitor visitor) 

class Health extends Stat 

    private int health 

    accept(StatVisitor visitor) 
     # or you can have visitor->visitHealth(this) 
     visitor->visit(this) 

    multiply(int mult) 
     this->health = this->health * mult 

class Strength extends Stat  

    private int strength 

    accept(StatVisitor visitor) 
     visitor->visit(this) 

    add(int strength) 
     this->strength = this->strength + strength 

Статистика являются "Элементы" узора для посетителей.Thing класс представляет "Клиент":

# Thing contains stats, this is Client 
class Thing 

    StatsList stats 

    accept(StatsVisitor visitor) 
     for stat in this->stats 
      stat->visit(visitor) 

И "Посетители" наши пункты, которые могут изменить статистику:

# Base visitor class 
class StatVisitor 

    abstract visit(Health health) 
    abstract visit(Strength strength) 

class MagicMirror 

    # magic mirror multiplies health by 10 
    visit(Health health) 
     health->multiply(10) 

    # magic mirror increases strength +5 
    visit(Strength strength) 
     strength->add(5) 

Теперь вы можете сделать это:

thing = new Thing() 
item = MagicMirror() 
# now update all the stats with MagicMirror 
thing->accept(item) 
0

Дон» t overcomplicate things:

  1. Кольцо регенерации: позволяет персонажу восстанавливать здоровье со временем

    Это действительно не должно изменять ваш объект вообще. Например. добавление кольца может добавить таймер, который пытается увеличить здоровье сущностей (то есть пользователь) и снятие звонка снова удаляет этот таймер.

  2. Снеаки кроссовок: увеличивается проскользнуть

    Это может быть смоделированы как модификация о Всей статистике:

    class Entity 
    
        Map<Skill, SortedList<Modifier>> skillModifiers 
    
        getSneakChance() 
         sneakChance = .. // compute base value from attributes 
         for each mod in skillModifiers[SneakChance] 
          sneakChance = mod.apply(sneakChance) 
         return sneakChance 
    

    Карта позволяет избежать два недостатков декоратора и цепи из-ответственности: не каждый модификатор добавляет еще одну косвенность к оценке, и у вас могут быть более простые модификаторы, основанные на значении (увеличение значения на x%), в отличие от нажатия логики того, какой stat/навык должен быть изменен или как получить доступ к нему в модификаторе als о.

    Одна из трудностей заключается в определении того, в каком порядке применять модификаторы: следует ли сначала добавить 20 к урону от атак, а затем увеличить его на 5% или наоборот, потеряв 1 пункт урона? Если определенные модификаторы применяются только к базовому значению, т. Е. Вам нужно передать как накопленное, так и базовое значение в mod.apply?

  3. Волшебное зеркало: отражает% входящего урона

    же, как и 2. На этот раз карты модификаторов и реакции на конкретные события (т.е. урона). Это позволяет использовать тот же эффект для нескольких объектов, таких как аура или какое-то другое заклинание аоэ.

  4. Doofy очки: основные крафта ресурсы

    Это опять-таки то, что не влияет на сущность. Gui-контроллер требует такой информации, поэтому просто запрашивайте плеер для визуальных модификаторов (если только каждый объект в вашей игре не должен манипулировать поведением и внешним видом вашего gui).

 Смежные вопросы

  • Нет связанных вопросов^_^