如何创建可以创建另一个类的实例并访问所有者的私有成员的类

时间:2010-02-19 15:56:13

标签: c# class inheritance oop

我不确定我想要做什么会违反面向对象的指导方针,所以我会解释我在做什么,希望如果我错了,你们可以告诉我一个更好的方法。我之前尝试过问这个问题,但是我给出了一个很糟糕的例子,所以我认为这只会引起更多混乱。

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

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

所以这就是我到目前为止......

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

4 个答案:

答案 0 :(得分:3)

由于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 :(得分:1)

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

只要您的报告类标记为public,您就可以执行以下操作:

Report r = new Report();

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

答案 2 :(得分:1)

以下会做你想要的。我们的想法是从实际实现中分离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();
    }        
} 

答案 3 :(得分:0)

为什么不通过全班(通过引用或复制)?

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

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


...
 class Report
        {
            ParentClassWithStream PC
            Report(ParentClassWithStream p)
            {
                PC = p

                //...
            }
            Send()
            {
                //send the data
            }
        }
...