【问题标题】:2 classes implement same interface, duplicated code2个类实现相同的接口,重复的代码
【发布时间】:2014-03-05 06:26:21
【问题描述】:

我有一个界面:

public interface IUser
{

}

然后是实现这个接口的2个类:

public class User : IUser 
{

}

public class AdminUser : IUser
{

}

现在我看到的问题是,在接口中实现方法时,User 和 AdminUser 之间存在重复代码。

我可以引入一个抽象类,以某种方式实现 User 和 AdminUser 之间的公共代码吗?

我不希望 AdminUser 从 User 继承。

【问题讨论】:

  • 答案是:可以的
  • 我认为正确的答案可能是:你用错了接口,抽象类可能不如组合有效。

标签: c# .net oop interface


【解决方案1】:

是的。可以的。

public abstract class BaseUser : IUser
{

}

public class User : BaseUser 
{

}

public class AdminUser : BaseUser
{

}

【讨论】:

    【解决方案2】:

    听起来您应该引入一个 UserBase 类,UserAdminUser 都可以从该类继承并具有共享代码

    class UserBase : IUser { 
    
      // Shared Code
    
    }
    
    class User : UserBase { } 
    
    class AdminUser : UserBase { } 
    

    【讨论】:

    • 你为什么选择不让 UserBase 成为一个抽象类?
    • @TravisJ OP 没有指定共享代码是否可以独立。如果定义中没有包含抽象成员,那么有一个抽象基础会觉得很奇怪。
    • 我明白了,这很有道理。
    【解决方案3】:

    您的类User 应该是AdminUser 的基类


    从类的名称看来,您的类 User 应该是基类,AdminUser 应该从该类继承。如果不是这种情况,那么您可以为UserAdminUser 创建一个基类,在基类中实现您的接口,并在UserAdminUser 中继承它。

    public interface IUser
    {
        void SomeMethod();
    }
    
    
    public abstract class User : IUser
    {
        public abstract void SomeMethod();
    }
    
    public class AdminUser : User
    {
        public override void SomeMethod()
        {
            throw new NotImplementedException();
        }
    
    }
    
    public class NormalUser : User
    {
        public override void SomeMethod()
        {
            throw new NotImplementedException();
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      是的,您可以在功能相同的抽象中创建具体方法。

      创建有共同需求但实现不同的虚拟方法

      然后在您的继承类中,为每个类添加对其实现唯一的方法

      【讨论】:

        【解决方案5】:

        你的问题的核心是你似乎试图使用接口来描述一个类是什么,而不是它的功能。接口最好用于指定 IAuthorizeable 或 IEnumerable 等内容。它们表明在一个共同主题上的不同行为。

        对于像您这样的情况,正如其他人所建议的那样,您希望使用继承,除非您可以更改构建事物的方式。我的偏好是创建一个包含不同部分策略的用户类,而不是继承。

        继承共享功能和允许差异可扩展之间存在很大差异。如果你用接口编写User而不是创建基类,如果将来需要添加更多角色,你只需要添加改变行为的另一个实现,而不是创建另一个可能与另一个共享不同事物的子类两个班。

        一个例子:

        class User
        {
          private IAuthenticator authenticator;
          public string Name { get; set; }
          public Guid Id { get; set; }
          public User(string name, Guid id, IAuthenticator authenticator)
          {
            Name = name;
            Id = id;
            this.authenticator = authenticator;
          }
          public Rights Authenticate()
          {
            return authenticator.Authenticate(Name, Id);
          }
        }
        

        身份验证器可能是这样的:

        public class WebAuthenticator : IAuthenticator
        {
          public Rights Authenticate(string name, Guid id)
          {
            // Some web specific authentication logic
          }
        }
        

        和权利:

        [Flags]
        public enum Rights
        {
          None = 0, Read = 1, Write = 1 << 1, Execute = 1 << 2
        }
        

        最终结果是您的代码可重用、可扩展且灵活。一般来说,用户是管理员这一事实不应该给用户类额外的逻辑,而是限制使用特定实例的东西。

        【讨论】:

          【解决方案6】:

          这就是接口而不是抽象类的问题:没有共享实现。接口旨在作为缺乏多重继承的解决方法。

          一般来说,您的对象模型应该是小型继承树的森林。

          一种解决方案是创建一个小的混合类,它提供所需的功能并实现接口。将其包含在您的类中,并通过调用 mix-in 实现接口的传递方法公开其方法。

          interface IFoo
          {
            int MethodA() ;
            int MethodB() ;
          }
          class IFooMixin : IFoo
          {
            public int MethodA() { ... }
            public int MethodB() { ... }
          }
          class Widget : IFoo
          {
            private IFooMixin IFooImplementation = new IFooMixin() ;
            public int MethodA()
            {
               int rc ;
               // inject your specific behavior here
               rc = IFooImplementation.MethodA() ;
               // and/or inject it here
               return rc ;
            }
            public int MethodB()
            {
               int rc ;
               // inject your specific behavior here
               rc = IFooImplementation.MethodB() ;
               // and/or inject it here
               return rc ;
            }
          

          【讨论】:

          • 我真的怀疑由于缺少 MI 而添加了接口。使用它们的原因有很多,例如强制执行合同 - 在这种情况下,它们可以被认为比继承“更安全”,因为您知道在基类中无需担心其他逻辑。将它们归类为解决方法就是忽略它们的单独目的。
          猜你喜欢
          • 2021-08-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-29
          • 2014-10-25
          • 2023-04-05
          • 1970-01-01
          • 2021-05-02
          相关资源
          最近更新 更多