Как создать класс, который может создать экземпляр другого класса и получить доступ к закрытым членам владельца - PullRequest
0 голосов
/ 19 февраля 2010

Я не уверен, что то, что я хочу сделать, нарушает объектно-ориентированные рекомендации или нет, поэтому я объясню, что я делаю, и, надеюсь, вы, ребята, сможете показать мне лучший способ, если я ошибаюсь. Я пытался задать этот вопрос раньше, но я привел плохой пример, так что я думаю, что это вызвало еще большую путаницу.

Итак, у меня есть основной класс, USBCommunicator. Конструктор принимает идентификатор продукта того типа устройства, с которым вы хотите общаться. У класса USBCommunicator также есть свойство для определенного серийного номера, с которым можно общаться. USBCommunicator имеет методы OpenConnection и CloseConnection, которые открывают или закрывают поток данных для передачи данных между устройством USB и ПК.

Для отправки данных через поток я хочу, чтобы USBCommunicator мог создавать экземпляр класса Report, устанавливать некоторые параметры, такие как тайм-ауты, ReportID и т. Д., А затем вызывать метод Send () класса Report для фактической отправки данные. Я не думаю, что какой-либо другой класс, кроме USBCommunicator, сможет создать экземпляр класса Report. (Например, Лодка не должна создавать экземпляры класса 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 ]

3 голосов
/ 19 февраля 2010

Поскольку 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 голос
/ 19 февраля 2010

Следующее будет делать то, что вы хотите. Идея состоит в том, чтобы отделить интерфейс для класса 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();
    }        
} 
1 голос
/ 19 февраля 2010

Вы не имеете явного доступа к закрытым членам, вы предоставляете открытые свойства, которые возвращают закрытые переменные из вашего класса Report.

Также, пока ваш класс отчета помечен public, вы можете сделать:*

Report r = new Report();

В вашем основном классе USBCommunicator.Но никогда не выставляйте переменные-члены как общедоступные, они должны быть закрытыми в Report, но вы должны включить открытые свойства для доступа к этим закрытым членам.

0 голосов
/ 19 февраля 2010

Почему бы вам не передать весь класс (по ссылке или копии)?

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

myUSB.Report должен иметь закрытого члена для хранения ссылки.


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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...