Разработка ООП вопрос по шаблону декоратора и стратегии C # - PullRequest
2 голосов
/ 13 февраля 2009

Скажем, к примеру, у вас есть базовый абстрактный класс

public abstract Foo
{
  IFlyable _fly;
  ISwimmable _swim;

  void performSwim()
  {
    _swim.swim();
  }

 void performFly()
 {
   _fly.fly();
 }
}

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

interface IFlyable { void fly(); }
interface ISwimmable { void swim(); }
interface IVoteable { void vote(); }

и т. Д.

Теперь у вас есть несколько классов, которые реализуют это, с конкретным IFlyable, ISwimmable и т. Д.

class Bar: Foo { _swim = new ConcerteSwim(); }
class Baz: Foo { _fly = new ConcreteFly(); }

и т. Д.

Один из них использует шаблон стратегии в базовом классе Foo для изменения поведения.

Мы могли бы также использовать шаблон декоратора, чтобы обернуть его определенным поведением, но, поскольку декоратор обертывает его базовым классом, как мы на самом деле позволяем принципу открытого закрытия работать, не касаясь базового класса, если позже мы добавим больше поведений к объекты. Так как это поведение может иметь разные сигнатуры, когда мы добавляем больше, а не просто, например, как вызов в декораторе

void performSwim()
{
     swimWithMoreSpeed() + foo.performSwim()
}

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

например я хочу иметь класс

public class XYF: Foo
{

}

Но я хочу дать ему некоторое поведение ISomeBehaviour, есть ли способ, которым я мог бы сказать, обернуть его таким типом поведения, или, скорее, вот как ConcreteFoo обернуть его этим поведением и теперь делать вещи, а не реализовывать интерфейс на конкретном xyz, хотя это заставляет вас реализовывать так много видов конкретных поведенческих классов, как swimbehaviour, nullbehaviour и т. д., но выхода из этого нет.

Есть ли способ сделать это в шаблонах проектирования? Это почти похоже на гибрид шаблонов.

Я знаю, что кажется, что если он ходит, как утка, и крякает, как утка, но требует батареи, тогда у вас что-то не так с абстракцией.

Надеюсь, это имеет смысл.

Ответы [ 3 ]

3 голосов
/ 13 февраля 2009

Попробуйте шаблон декоратора. Для поддержки нового поведения вы просто реализуете новый класс, который наследуется от Foo, реализует IWeaponBehavior и украшает другой объект Foo. Теперь вы можете использовать WeaponDecorator как Foo или IWeaponBehavior и по-прежнему иметь доступ к базе Foo, которую он украшает.

Базовый класс:

public abstract Foo { void Jump(); }

Конкретные подклассы с базовым поведением:

public Bar : Foo { void Jump() { /* jump! */ } }
public Baz : Foo { }

Интерфейсы поведения:

interface IFlyable { void Fly(); }
interface ISwimmable { void Swim(); }

Подклассы декоратора с поведением:

public FlyableFoo : Foo, IFlyable
{
    public Foo Base { get; set; }
    public FlyableFoo(Foo base) { Base = base; }
    void Fly() { Base.Jump(); /* fly! */ }
}

Теперь мы можем сделать любую Foo муху, используя ее конкретную реализацию Jump():

Baz baz = new Baz();
FlyableFoo flybaz = new FlyableFoo(baz);
flybaz.Fly();
0 голосов
/ 17 февраля 2009

Как насчет шаблона посетителя? Это позволяет разработчикам вашего базового класса изменять поведение, не заставляя базовый класс меняться для каждой новой реализации:

public interface IFlyable { void fly(); }
public interface ISwimmable { void swim(); }
public interface IVoteable { void vote(); }

public abstract class Animal
{
    public abstract void Accept(AnimalVisiter Visitor);
    //some common behaviour is here
    public bool LegsKicking { get; set; }
    public bool ArmsFlapping { get; set; }
}

//This class now absorbs new responisbilities, so base class doesn't have to
public class AnimalVisiter
{
    public void Visit(ISwimmable Subject)
    {
        Subject.swim();
    }

    public void Visit(IVoteable Subject)
    {
        Subject.vote();
    }

    public void Visit(IFlyable Subject)
    {
        Subject.fly();
    }
}

public class SwimmingHuman : Animal, ISwimmable
{
    public void swim()
    {
        LegsKicking = true;
    }

    public override void Accept(AnimalVisiter Visitor)
    {
        Visitor.Visit(this);
    }
}

public class VotingHuman : Animal, IVoteable
{

    public override void Accept(AnimalVisiter Visitor)
    {
        Visitor.Visit(this);
    }

    public void vote()
    {
        VoteCast = true;
    }
    //some specific behaviour goes here
    public bool VoteCast { get; set; }
}

public class SwimmingTiger : Animal, ISwimmable
{

    public void swim()
    {
        LegsKicking = true;
        //also wag tail, flap ears
    }

    public override void Accept(AnimalVisiter Visitor)
    {
        Visitor.Visit(this);
    }
}
0 голосов
/ 13 февраля 2009

Итак, вот мой взгляд на это:

public enum ActionType
{
   Swim, Vote, Fly
};

public interface IBehavior
{
   public boolean ActionReady;
   public ActionType _type;

   public void performMyAction();
}

public abstract Foo
{
  IBevahior[] behaviors;

  // if you want to keep track of behavior states as on or off
  void perform()
  {
    for(int i = 0; i< behaviors.length; i++)
    {
       if(behaviors[i].ActionReady)
       {
          behaviors[i].performMyAction();
       }
    }
  }

  // if you want to call behaviors individually
  void performType(ActionType type)  // however you want to make the distinction
  {
     for(int i = 0; i < behaviors.length; i++)
     {
        if(behaviors[i].type = type)
        {
            behaviors[i].performMyAction();
        }
     }
  }
}

и ваши интерфейсы, такие как ISwimmable и т. Д., Наследуются от IBehavior.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...