Вопрос о программировании: глобальный объект - PullRequest
2 голосов
/ 04 августа 2009

У меня, вероятно, довольно простая проблема, но я пока не нашел правильного проектного решения. По сути, у меня есть 4 разных класса, и у каждого из них более 10 методов.

Каждый из этих классов должен использовать один и тот же сокет TCP; этот объект сохраняет сокет открытым для сервера на протяжении всего выполнения программы. Моя идея состояла в том, чтобы объявить объект TCP «глобальным», чтобы все остальные классы могли его использовать:

classTCP TCPSocket;

class classA  
{  
    private:   
    public:   
    classA();  
    ...   
};    

class classB  
{  
    private:   
    public:   
    classB();  
    ...   
};    

К сожалению, когда я объявляю это так, мой компилятор C ++ выдает мне сообщение об ошибке, что некоторые исполняемые данные записываются в исполняемый файл (???) Поэтому мне интересно, есть ли другой способ объявить этот объект TCP, чтобы он был доступен для ВСЕХ других классов и его методов?

Большое спасибо!

Ответы [ 7 ]

9 голосов
/ 04 августа 2009

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

4 голосов
/ 05 августа 2009

Мне кажется, что в нужный момент лучше использовать Dependency Injection, так как я стараюсь избегать Синглтона как можно больше (Синглтон - это еще один способ доступа к GLOBLAS, и его следует избегать)

Singleton vs Dependency Injection уже обсуждалось на SO, проверьте тег «внедрение зависимостей» (извините, что не публикую некоторые ссылки, но SO не позволяет мне публиковать более одной ссылки, будучи новым пользователем)

Википедия: Внедрение зависимостей

В соответствии с вашим текущим примером кода, должен быть изменен, чтобы разрешить внедрение Socket в конструктор каждого класса:

class classA  
{  
    private:   
    public:   
    classA(TCPSocket socket);  
    ...   
};    

class classB  
{  
    private:   
    public:   
    classB(TCPSocket socket);  
    ...   
};
4 голосов
/ 04 августа 2009

Это звучит как работа для шаблона проектирования Singleton .

1 голос
/ 04 августа 2009

Передайте сокет в конструктор каждого объекта. Затем создайте отдельный фабричный класс , который создает их и передает в соответствующий сокет. Весь код использует набор объектов, которые должны иметь один и тот же сокет, и затем должны создавать их через экземпляр этого фабричного объекта. Это разъединяет классы, которые должны использовать один сокет, и в то же время позволяет применять правило общего сокета.

0 голосов
/ 06 августа 2009

Как все уже говорили, глобалы плохие и т. Д.

Но чтобы на самом деле устранить ошибку компиляции, которая у вас есть, я почти уверен, что это потому, что вы определяете глобальное в заголовочном файле, который включен в несколько файлов. То, что вы хотите, это:

something.h

extern classTCP TCPSocket; //global is DECLARED here

class classA  
{  
    private:   
    public:   
    classA();  
    ...   
};

something.cpp

classTCP TCPSocket; //global is DEFINED here
0 голосов
/ 05 августа 2009

Когда у вас есть объект, который является уникальным в вашей программе и используется во многих местах, у вас есть несколько вариантов:

  • передать ссылку на объект везде

  • использовать глобальный более или менее хорошо скрытый (синглтон, моносостояние, ...)

У каждого подхода есть свои недостатки. Они довольно хорошо прокомментированы, и у некоторых есть очень сильные мнения по этим вопросам (выполните поиск «единого антишаблонного») Я просто дам некоторые из них, и не буду пытаться быть полным.

  • Передача ссылки утомительна и загромождает код; так что в итоге вы сохраняете эти ссылки в каком-то долгоживущем объекте, чтобы уменьшить количество параметров. Когда придет время, когда «уникальный» объект больше не будет уникальным, вы готовы? Нет: у вас есть несколько путей к уникальному объекту, и вы увидите, что они теперь ссылаются на разные объекты и используются непоследовательно. Отладка этого может быть кошмаром хуже, чем модификация кода от глобального подхода к пассивному подходу, и худшее не планировалось в расписаниях, поскольку код был готов.

  • Проблема глобального подобного подхода еще более известна. Они вводят скрытые зависимости (таким образом, повторное использование компонентов более сложно), неожиданный побочный эффект (получение правильного поведения более сложно, исправление ошибки где-то вызывает ошибку в других компонентах), тестирование более сложное, ...

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

0 голосов
/ 04 августа 2009

Лучший способ сделать это - синглтон. Вот его реализация на Java

Класс Singleton:

public class SingletonTCPSocket {
  private SingletonTCPSocket() {
    // Private Constructor
  }

  private static class SingletonTCPSocketHolder { 
    private static final SingletonTCPSocket INSTANCE = new SingletonTCPSocket ();
  }

  public static SingletonTCPSocket getInstance() {
    return SingletonTCPSocket.INSTANCE;
  }

  // Your Socket Specific Code Here
  private TCPSocket mySocket;
  public void OpenSocket();
}

Класс, которому требуется сокет:

public class ClassA {
  public ClassA {
    SingletonTCPSocket.getInstance().OpenSocket();  
  }  
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...