【问题标题】:How to decide when to use inheritance or just use the functionality of the base class如何决定何时使用继承或仅使用基类的功能
【发布时间】:2017-04-12 05:03:05
【问题描述】:

我对 OOP 中的继承概念有一些疑问。当我刚刚完成自定义类的编码以连接数据库时。
例如

   `// for encapsulate some method under and use as the team's custom 
    // version of DBconnect
   public class DBconnector()
   {
      public void SetConnection(); // setting 
      public void BeginCon(); // setting 
      public void SetQuery(String i_Query , CommandType cmdType); // setting 
      public Object GetExcetue();
     ... // other setting 
   }` 

然后系统具有单独的业务逻辑分类,将为其模块获取内容(来自数据库的数据),例如 BusinessLogicM1 、 BusinessLogicM2 、 BusinessLogicM3 ...
这些单独的分类将通过使用 DBconnector 的功能从 Db 获取数据。所以我在这里混淆是否应该通过从 DBconnector 类继承来编码 BusinessLogic 类,只使用 DBconnector 的方法。
public class BusinessLogicX :DBconnector { public Object GetXData() { ...// setting return this.GetExcetue(); } }
public class BusinessLogicX { public Object GetXData() { var service = new DBconnector(); ...//setting return service.GetExcetue(); } }

【问题讨论】:

    标签: c# oop inheritance


    【解决方案1】:

    应根据类的预期功能来驱动继承。在您的情况下,DBConnector 类的功能是管理数据库连接/查询,而 BusinessLogicX 类的功能是实现业务逻辑。因此这两个类不相关,因此不应该有继承。 我建议你应该只使用 DBConnector 类的方法。

    在您的 BusinessLogic 实现中,如果 BusinessLogicM1 、 BusinessLogicM2.. 共享任何共同行为,那么您应该将继承构建为

    class BaseBusinessLogic
    {
        public void commonMethod1() 
        {
        }
        public void commonMethod2() 
        {
        }
    
        public Object GetXData()
        { 
                var service = new DBconnector();
                ...//setting
                return service.GetExcetue();
        }
    }
    
    
    Class BusinessLogicM1 : BaseBusinessLogic
    {
          public void M1LogicMethod()
          {
              ..........
          }
    }
    

    您也可以考虑将 DBConnector 设为 BaseBusinessLog 类的成员,这样就可以在一个地方维护数据库连接。

    ...以 DBConnector 作为成员的 BaseBusinessLogic 类示例

    class BaseBusinessLogic
    {
    
        private DBconnector _connector;
    
        public void initConnector( DBConnector iConnector)
        {
            this._connector =  iConnector;
        }
    
        public void commonMethod1() 
        {
        }
        public void commonMethod2() 
        {
        }
    
        public Object GetXData()
       { 
    
                ...//setting
                _connector.SetQuery("..."); // Query to get 'X' Data
                return _connector.GetExcetue();
        }
    }
    
    
    Class BusinessLogicM1 : BaseBusinessLogic
    {
          public void M1LogicMethod()
          {
              // Fetch DataList from DBConnector
              _connector.SetQuery(".....");
              Object obj = _connector.GetExecute();
    
              Object xData = GetXData();
    
              // use obj and xData Object to build BusinessLogicM1
          }
    }
    

    【讨论】:

    • 如果 BusinessLogicX 类打算从 DB 中查询其模块的数据,这不意味着 BusinessLogicX 类具有与 DBConnector 相同的功能(可以连接到 DB)吗?我认为 businessLogicX 类与 DBConnector 类有关,因为它必须具有并且能够从数据库中检索数据。或者我只是从一开始就误解/误解了事情?
    • 如果你为BusinessLogicX类构建继承,那么正如我之前写的,BaseBusinessLogic类可以有DBConnector对象作为成员变量,所有子类都可以使用它来查询数据库。 (在下面的另一个答案中添加示例)
    【解决方案2】:

    如果 BusinessLogicX 类打算从中查询其模块的数据 DB,是不是说BusinessLogicX类也一样 DBConnector 的功能(它可以连接到数据库)?

    没有。这是不正确的,BL(业务逻辑)和 DB(存储)之间的继承是没有问题的。

    关注点分离

    您的业务类只需要数据,不应该关心检索数据的机制。事实上,它甚至不应该知道数据是从 MSSQL、Oracle 还是简单的基于文件的数据源中检索的。这就是数据访问层或类的所有问题。当你去咖啡店时,对你来说最重要的是你点了一杯咖啡,而不是他们是如何准备的!

    正如@milindmb 正确指出的那样,如果适用,您应该将常见行为放在基本 BL 中。您可以将基础 BL 标记为 abstract 而不是具体的。

    DbConnector

    我建议为此定义一个interface 并将其实现注入 BL 类作为依赖项。请注意,接口对于依赖注入不是必需的。您可以注入类类型以及@milinmb 的基础 BL 类中所示的类型。接口具有额外的优势,即如果/当您对业务逻辑类进行单元测试时,它们可以被模拟。那是另一个故事。因此,您的商务舱通常如下所示(我喜欢称它们为服务。这是您的选择):

    public abstract class ServiceBase {
        protected readonly IDbConnector dbConnector;
    
        public ServiceBase(IDbConnector dbConnector) {
            this.dbConnector = dbConnector;
        }
    }
    
    public class UserService : ServiceBase {
        public UserService(IDbConnector dbConnector) : base(dbConnector) {
        }
    
        // use dbConnector from ServiceBase 
    }
    

    拥有IDBConnector 意味着,将来您将能够根据您使用的数据源注入不同的实现,例如:SqlConnector、OracleConnector 等。上面显示了构造函数注入,这是一种依赖注入(DI )。还有方法和设置器(使用属性)注入。因为有时依赖项是可选的,您可能希望创建类实例而不注入它们。详细了解 DI。

    存储库

    这将超出范围,所以我把这个留给你研究。检查 Google 是否使用了构成应用程序数据访问层的存储库。它们的使用取决于您的应用程序的范围。

    【讨论】:

    • 非常感谢您澄清@milindmb 的回答并指出我的观点哪里出了问题。您能否进一步解释“接口增加了可以模拟的优势”。我的意思是如果服务类注入了 Dbconnector 类(而不是定义接口),就不能测试服务类吗?
    • 请在线阅读这些内容。有很多可用的材料,人们自古以来就一直在这样做。你可以从msdn.microsoft.com/en-us/library/ff650441.aspx开始
    猜你喜欢
    • 2012-03-09
    • 2015-09-25
    • 2022-12-04
    • 1970-01-01
    • 2023-03-23
    • 2018-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多