关于装饰器和策略模式C#的设计OOP问题

时间:2009-02-12 21:06:44

标签: c# oop design-patterns decorator strategy-pattern

比如说你有一个基础抽象类

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基类中的策略模式来交换行为。

我们也可以使用装饰器模式用某种行为来包装它,但是由于装饰器用基类包装它,如果我们以后添加更多行为,我们如何实际允许open close原则工作而不触及基类对象。由于这些行为可能会有不同的签名,因为我们添加更多,而不仅仅是例如调用装饰器

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

我想我的问题是,如果我添加更多行为,我怎么能不修改基类,仍然可以说将IWeaponBehavior,ISomeBehaviour添加到类中。

例如我想要一个班级

public class XYF: Foo
{

}

但是我想给它一些ISomeBehaviour的行为,有没有办法可以用这些行为来包装它,或者更像是这里是一个ConcreteFoo用这些行为包装它现在做的东西而不是实现接口在具体的xyz上,虽然这会让你实现如swimbehaviour,nullbehaviour等许多类型的具体行为,但是没有办法摆脱它。

有没有办法在设计模式中这样做?它几乎看起来像模式的混合。

我知道,如果它像鸭子一样行走,像鸭子一样呱呱叫,但需要电池,那么抽象就有问题。

希望这是有道理的。

3 个答案:

答案 0 :(得分:3)

尝试装饰器模式。要支持新行为,您只需实现一个继承自Foo,实现IWeaponBehavior并装饰另一个Foo对象的新类。然后,您现在可以将WeaponDecorator用作FooIWeaponBehavior,并仍然可以访问其装饰的基础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();

答案 1 :(得分:0)

访客模式怎么样?它允许基类的实现者改变行为,而不必强制基类改变每个新实现:

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);
    }
}

答案 2 :(得分:-2)

所以这是我对此的看法:

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。