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

发布于 2024-07-13 09:58:46 字数 1255 浏览 6 评论 0原文

举例来说,你有一个基础抽象类

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 等,但没有办法摆脱它。

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

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

希望这是有道理的。

Say for example you have a base abstract class

public abstract Foo
{
  IFlyable _fly;
  ISwimmable _swim;

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

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

And have behaviors/algorithm that you will have in your system

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

etc etc

Now you have multiple class that implement it, with concrete of IFlyable, ISwimmable etc

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

etc etc

One is using the strategy pattern in the base class of Foo to swap in the behaviours.

We could also use the decorator pattern to wrap it with certain behavior but since the decorator wraps it with base class, how do we actually allow the open close principle to work without touching the base class if we later on add more behaviors to objects. Since these behavior might have different signatures as we add more, rather than just for example like calling in decorator

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

I guess my question is if I add more behavior, how can I not modify the base class and still be able to say add IWeaponBehavior, ISomeBehaviour to a class.

for example I want to have a class

public class XYF: Foo
{

}

But I want to give it some behavior of ISomeBehaviour, is there a way I could say wrap it with these kinds of behaviour, or more like here is an ConcreteFoo wrap it with these behaviours and now do stuff rather than implementing the interface on concrete xyz although that makes you implementing so many kinds of concretebehaviour class like swimbehaviour, nullbehaviour etc but there is no way out of it.

Is there a way to do this in design patterns? It almost seems like a hybrid of patterns.

I know it almost seems like if it walks like a duck and quacks like a duck but requires battery then you have something wrong with abstraction.

Hope this make sense.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

滥情哥ㄟ 2024-07-20 09:58:46

尝试装饰器模式。 要支持新行为,您只需实现一个继承自 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! */ }
}

现在我们可以使用其特定的 Jump() 实现来使任何 Foo 飞行:

Baz baz = new Baz();
FlyableFoo flybaz = new FlyableFoo(baz);
flybaz.Fly();

Try the decorator pattern. To support a new behavior, you would just implement a new class that inherits from Foo, implements IWeaponBehavior, and decorates another Foo object. Then you can now use the WeaponDecorator as a Foo or IWeaponBehavior and still have access to the base Foo that it decorates.

Base class:

public abstract Foo { void Jump(); }

Concrete subclasses with base behavior:

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

Behavior interfaces:

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

Decorator subclasses with behavior:

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

Now we can make any Foo fly, using its particular implementation of Jump():

Baz baz = new Baz();
FlyableFoo flybaz = new FlyableFoo(baz);
flybaz.Fly();
夏の忆 2024-07-20 09:58:46

访客模式怎么样? 它允许基类的实现者改变行为,而无需强制基类针对每个新实现进行更改:

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

How about the visitor pattern? It allows implementors of your base class to vary behaviours without forcing the base class to change for each new implementation:

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);
    }
}
乖乖公主 2024-07-20 09:58:46

所以这是我对此的看法:

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。

So here's my take on this:

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

and then have your interfaces like ISwimmable, etc inherit from IBehavior.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文