【问题标题】:How do I make a class that can create an instance of another class and access private members of the owner如何创建一个可以创建另一个类的实例并访问所有者的私有成员的类
【发布时间】:2010-02-19 15:56:13
【问题描述】:

我不确定我想做的事情是否违反了面向对象的准则,所以我会解释我在做什么,如果我错了,希望你们能告诉我一个更好的方法。我之前尝试过问这个问题,但我举了一个糟糕的例子,所以我认为它只会造成更多的混乱。

所以我有一个主类,USBCommunicator。构造函数采用您要与之交谈的设备类型的产品 ID。 USBCommunicator 类还有一个属性,用于与特定的序列号进行通信。 USBCommunicator 具有 OpenConnection 和 CloseConnection 方法,它们将打开或关闭数据流以在 USB 设备和 PC 之间传输数据。

为了通过流发送数据,我希望 USBCommunicator 能够创建一个 Report 类的实例,设置一些参数,例如超时、ReportID 等,然后调用 Report 类的 Send() 方法来实际发送数据。我认为除了 USBCommunicator 之外的任何类都不能创建 Report 类的实例。 (例如,Boat 女士不应该能够创建 CarDoor 类的实例,因为船不能有车门。)最后,我最初认为 Report 类应该能够访问 USBCommunicator 的成员但我想这不是真的。如果 USBCommunicator 打开设备的流,所有 Report 真正需要的是传入的参数,它是对打开流的引用/句柄。但是该流应该是什么形式才能允许它被高级应用程序传递?公共财产?这似乎不太对。

这就是我目前所拥有的......

namespace USBTools
{
    class HighLevelApplication
    {
        void main()
        {
            USBCommunicator myUSB = new USBCommunicator("15B3");
            myUSB.SerialNumber = "123ABC";
            myUSB.OpenConnection();
            myUSB.Report ReportToSend = new myUSB.Report(//how do I pass the stream here?);
                //It would be nice if I didn't have to pass in the stream because the stream shouldn't
                //be publicly available to the HighLevelApplication class right?
            ReportToSend.ReportID = 3;
            ReportToSend.Timeout = 1000;
            ReportToSend.Data = "Send this Data";
            ReportToSend.Send();
        }
    }

    class myUSB
    {
        myUSB(string PID)
        {
            //...
        }

        // public SerialNumber property

        // private stream field ???

        // public OpenConnection and CloseConnection methods

        class Report
        {
            Report(stream StreamToUse)
            {
                //...
            }
            Send()
            {
                //send the data
            }
        }
    }
}

【问题讨论】:

    标签: c# class inheritance oop


    【解决方案1】:

    由于USBCommunicator 管理所有重要资源(包括流的生命周期),应用程序应该调用USBCommunicator.Send,而不是Report.Send

    public class USBCommunicator {
        public void Send(Report report) {
    
            // If it's appropriate, this method can also Open 
            // and Close the stream so callers don't have to.
    
            report.Send(this.stream);
        }
    }
    

    接下来,将 Report.Send 设为内部,这样它就不是公共 API 的一部分,应用程序可以这样做:

    public void main(string[] args) {
            USBCommunicator myUSB = new USBCommunicator("15B3");
            myUSB.SerialNumber = "123ABC";
            myUSB.OpenConnection();
    
            Report report = new Report(3, 1000, "Send this Data");
            myUSB.Send(report);
    }
    

    我认为除了 USBCommunicator 应该能够 创建报告的实例 类。

    您当前的设计并没有阻止这一点 - 实际上,您的示例应用程序创建了一个 Report 类的实例。如果你真的想隐藏报告类,你应该把它设为USBCommunicator 的私有,并将其属性推送到通信器的接口,如下所示:

    // USBCommunicator
    public void Send(int reportID, int timeout, string data) {
        Report report = new Report(reportID, timeout, data);
        report.Send(this.stream);
    }
    

    【讨论】:

    • +1 - 我发布的内容提到了属性,但这是个好建议。
    【解决方案2】:

    您无需显式访问私有成员,而是提供从 Report 类返回私有变量的公共属性。

    同样只要你的报表类被标记为public,你可以这样做:

    Report r = new Report();
    

    在您的主要 USBCommunicator 类中。但永远不要将成员变量公开,它们在 Report 中应该是私有的,但您应该包含公共属性以访问这些私有成员。

    【讨论】:

      【解决方案3】:

      以下内容可以满足您的要求。这个想法是将 Report 类的接口与实际实现分开。这使您可以创建一个只有您的 USBCommunicator 对象才能创建的实现类。

      public abstract class Report
      {
         protected Report() { }
      
         public int ReportID {get; set;}
         public int Timeout {get; set;}
         public string Data {get; set; }
         public abstract void Send();
      }
      
      public class USBCommunicator 
      { 
          private Stream m_stream;
      
          public USBCommunicator (string PID) 
          { 
              //... 
          } 
      
          //Callers create new report objects via a method instead of directly using 'new'
          public Report CreateReport()
          {
              return new ReportImpl(m_stream);   
          }
      
          //Provides the implementation of the abstract methods of the Report class.
          private class ReportImpl : Report
          {
              private Stream m_stream;
      
              public ReportImpl(Stream stream)
              {
                 m_stream = stream;
              }
      
              public void override Send()
              {
                 //put implementation of Send here.
              }
          }
      }
      

      然后你的高级应用变成:

      class HighLevelApplication        
      {        
          void main()        
          {        
              USBCommunicator myUSB = new USBCommunicator("15B3");        
              myUSB.SerialNumber = "123ABC";        
              myUSB.OpenConnection();        
      
              Report reportToSend = myUSB.CreateReport();
      
              reportToSend.ReportID = 3;        
              reportToSend.Timeout = 1000;        
              reportToSend.Data = "Send this Data";        
              reportToSend.Send();
          }        
      } 
      

      【讨论】:

      • 那么我的报告类在哪里以及是什么阻止了 HighLevelApplication 执行此报告 reportToSend = new Report(); ?那会很糟糕,因为它没有流对吗?
      • Report 是抽象的,Send 没有实现,所以在继承 Report 并在其他地方实现 Send 之前,您将无法对它做任何事情。
      【解决方案4】:

      你为什么不通过整个课程(通过参考或复制)?

      myUSB.Report ReportToSend = new myUSB.Report(ParentClassWithStream);

      myUSB.Report 必须有一个私有成员来保存引用。

      ... class Report { ParentClassWithStream PC Report(ParentClassWithStream p) { PC = p //... } Send() { //send the data } } ...

      【讨论】:

      • 这不会违反面向对象的准则吗?
      • 如果你的父类尊重封装那么不行,因为你将使用你的访问方法来获取你需要的信息。这只是一个引用另一个类的类
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-18
      • 1970-01-01
      • 1970-01-01
      • 2016-02-21
      • 2017-12-15
      • 1970-01-01
      相关资源
      最近更新 更多