Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#有抽象类和接口,是否也应该有;混合;?_C#_Visual Studio_Design Patterns_Oop - Fatal编程技术网

C#有抽象类和接口,是否也应该有;混合;?

C#有抽象类和接口,是否也应该有;混合;?,c#,visual-studio,design-patterns,oop,C#,Visual Studio,Design Patterns,Oop,每隔一段时间,我就会遇到这样一种情况:我希望一组类都具有相似的逻辑。例如,我可能希望鸟和飞机都能飞行。如果您考虑的是“策略模式”,我会同意,但即使使用策略,有时也无法避免重复代码 例如,假设以下情况适用(这与我最近遇到的实际情况非常相似): Bird和Airplane都需要保存实现IFlyBehavior的对象实例 调用OnReadyToFly()时,Bird和frame都需要请求IFlyBehavior实例执行Fly() 调用OnReadyToLand()时,Bird和frame都需要向IFl

每隔一段时间,我就会遇到这样一种情况:我希望一组类都具有相似的逻辑。例如,我可能希望鸟和飞机都能飞行。如果您考虑的是“策略模式”,我会同意,但即使使用策略,有时也无法避免重复代码

例如,假设以下情况适用(这与我最近遇到的实际情况非常相似):

  • Bird
    Airplane
    都需要保存实现
    IFlyBehavior
    的对象实例
  • 调用
    OnReadyToFly()
    时,
    Bird
    frame
    都需要请求
    IFlyBehavior
    实例执行
    Fly()
  • 调用
    OnReadyToLand()
    时,
    Bird
    frame
    都需要向
    IFlyBehavior
    实例询问
    Land()
  • OnReadyToFly()
    onreadytofland()
    是私有的
  • 继承
    动物
    飞机
    继承
    人兽
  • 现在,假设我们稍后添加了
    Moth
    hotirballoon
    ,以及其他16个对象,假设它们都遵循相同的模式

    我们现在需要20份以下代码的副本:

    private IFlyBehavior _flyBehavior;
    
    private void OnReadyToFly()
    {
        _flyBehavior.Fly();
    }
    
    private void OnReadyToLand()
    {
        _flyBehavior.Land();
    }
    
    有两件事我不喜欢:

  • 它不是很枯燥(同样的九行代码被重复了一遍又一遍)。如果我们发现了一个bug,或者在
    IFlyBehavior
    中添加了一个
    BankRight()
    ,那么我们需要将更改分发给所有20个类

  • 没有任何方法可以强制所有20个类一致地实现这种重复的内部逻辑。我们不能使用接口,因为接口只允许公共成员。我们不能使用抽象基类,因为对象已经继承了基类,而C#不允许多重继承(即使这些类还没有继承类,我们以后可能希望添加一个新的行为来实现,比如,
    ICrashable
    ,所以抽象基类并不总是可行的解决方案)

  • 如果…?

    如果C#有一个新的构造,比如说
    模式
    模板
    或[在这里填写您的想法],它就像一个接口,但允许您在成员上放置私有或受保护的访问修饰符,该怎么办?您仍然需要为每个类提供一个实现,但是如果您的类实现了
    PFlyable
    模式,那么您至少可以强制每个类都有必要的样板代码来调用
    Fly()
    Land()
    。而且,使用像VisualStudio这样的现代IDE,您可以使用“ImplementPattern”命令自动生成代码

    就我个人而言,我认为将接口的含义扩展到任何合同,无论是内部(私有/受保护)还是外部(公共)都更有意义,但我建议首先添加一个全新的结构,因为人们似乎对“接口”一词的含义非常坚定,我不想让语义学成为人们回答的焦点

    问题:

    不管你怎么称呼它,我想知道我在这里建议的功能是否有意义。我们是否需要某种方法来处理由于限制性访问修饰符的需要或程序员无法控制的原因而无法提取出所需代码的情况

    更新

    从AakashM的评论中,我相信我所要求的功能已经有了一个名字:混音。所以,我想我的问题可以缩短为:“C是否应该允许混入?”

    你刚才描述的

    一个流行的C#AOP实现似乎是(主站点似乎关闭了/对我来说不起作用,直接的“关于”页面)


    后续评论:我不确定PostSharp是否支持,但我认为你在谈论AOP:

    类型间声明提供了一种方法 表达横切关注点 影响模块的结构。 这也被称为开放类 使程序员能够在一个 安置另一个人的成员或父母 类,通常是为了合并 与中某个问题相关的所有代码 一方面


    VisualStudio已经提供了带有代码片段的“穷人表单”。此外,有了重构工具a la ReSharper(甚至可能还有visualstudio中的原生重构支持),在确保一致性方面还有很长的路要走

    [编辑:我没有想到扩展方法,这种方法让你走得更远(你只需要将_flyBehavior作为一个私有变量)。这使得我的其余答案可能过时了…]

    但是,;只是为了讨论:如何改进?这是我的建议

    可以想象,未来版本的C#编译器将支持以下内容:

    // keyword 'pattern' marks the code as eligible for inclusion in other classes
    pattern WithFlyBehaviour
    {
       private IFlyBehavior_flyBehavior;
    
       private void OnReadyToFly()
       {
          _flyBehavior.Fly();
       }
    
       [patternmethod]
       private void OnReadyToLand()
       {
          _flyBehavior.Land();
       }     
    }
    
    然后你可以用它,比如:

     // probably the attribute syntax can not be reused here, but you get the point
     [UsePattern(FlyBehaviour)] 
     class FlyingAnimal
     {
       public void SetReadyToFly(bool ready)
       {
          _readyToFly = ready;
          if (ready) OnReadyToFly(); // OnReadyToFly() callable, although not explicitly present in FlyingAnimal
       }
    
     }
    

    这会是一种进步吗?可能真的值得吗?也许…

    我们不能为此使用扩展方法吗

        public static void OnReadyToFly(this IFlyBehavior flyBehavior)
        {
              _flyBehavior.Fly()
        }
    

    这模仿了您想要的功能(或混合)

    您描述的问题可以使用访问者模式解决(所有问题都可以使用访问者模式解决,所以要小心!)

    访问者模式允许您将实现逻辑移到一个新类中。这样,您就不需要基类,访问者在不同的继承树上工作得非常好

    总而言之:

  • 新功能不需要添加到所有不同的类型
  • 对访问者的调用可以上拉到每个类层次结构的根
  • 有关参考信息,请参见

    我将使用扩展名met
    public interface IFlyer 
    {  
        public IFlyBehavior FlyBehavior 
    }
    
    public Bird : IFlyer
    {
        public IFlyBehaviour FlyBehavior {get;set;}
    }
    
    public Airplane : IFlyer
    {
        public IFlyBehaviour FlyBehavior {get;set;}
    }
    
    public IFlyerExtensions
    {
    
        public void OnReadyToFly(this IFlyer flyer) 
        {
            flyer.FlyBehavior.Fly(); 
        }
    
        public void OnReadyToLand(this IFlyer flyer) 
        {
            flyer.FlyBehavior.Land(); 
        }
    }