LINUX.ORG.RU

Глобальные переменные, синглтоны и прочее зло


0

4

SUBJ
Как ограничить доступ к глобальному состоянию, разрешив только определенным классам чтение/модификацию (типа friend class в c++) определенного состояния? Использовать менеджер глобального состояния?
К примеру, есть 10 глобальных переменных и 20 классов, которые обращаются к некоторым из них.
Ясно, что отказавшись от глобальных переменных, придется передавать их через пол-кода, причем в этом коде потом кто-то по ошибке возьмет, да и модифицирует переменную. В итоге будет тот еще спагетти-код.

Тебе не доступ надо ограничивать, а от глобального состояния в явном виде избавляться. Тогда проблема отпадёт сама собой

yoghurt ★★★★★ ()

создаешь некий канал на некоей шине данных, адрес раскрываешь только избранным и ссылаешься только на него. Сущности в этом канале можно реализовать или задействовать встроенные/системные (если есть на это время и возможности) с правами доступа (от простейшего ALL, RO, RW, WO до учета владельцев, групп) или пока без них. Суть в том что в этом случае ограничивается «глобализация»

Дополнительные материалы:

+ близкие паттерны: регистр, посредник, умная ссылка (прокси)?

+ DI, IOC

+ IPC

вообще иммутабельность хорошо-бы

swwwfactory ★★ ()
Последнее исправление: swwwfactory (всего исправлений: 1)
Ответ на: комментарий от nerdogeek

Теоретически да, но практически хз как

Ну начни с замены обращений к глобальным объектам в коде на обращения к параметрам, которые указывались бы объектам, которые сейчас обращаются к глобальным.

yoghurt ★★★★★ ()

IoC же. Все стейтхолдеры через внедренные зависимости привязать.

Absurd ★★★ ()
Ответ на: комментарий от yoghurt

Проблема в том, что такие параметры нужно тянуть через много классов, которые как-бы «левые»: они просто тянут параметры, которые кому-то могут понадобиться. Причем число таких пар-в может быть пропорционально всем глобальным переменным (в каком-нить диспетчере). Надеюсь, более-менее понятно описал проблему

nerdogeek ()
Ответ на: комментарий от nerdogeek

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

С проверкой во время компиляции всё гораздо сложнее. Тут уже сильно зависит от языка.

  • В тсепепе, пожалуй, выручат френды.
  • В сишарпе и жаве можно запихнуть все глобальные переменные в синглтон с protected геттерами/сеттерами и поместить его в одну сборку/пакет с классами, которые должны уметь читать/изменять переменные.
  • Если нет возможности раскидывать классы по сборкам, то можно замутить следующее (на примере шарпа):
    1. Наследуем все классы, которые должны иметь доступ к переменным, от интерфейса, содержащего событие для изменения.
    2. В каждом классе подписываем синглтон на это событие.
    3. Обработчик в синглтоне будет иметь сигнатуру, принимающую события только от классов, реализующий указанный интерфейс.
    4. Когда классу нужно изменить переменную, он кидает событие. Если левый класс попробует кинуть, то обработчик не вызовется по понятным причинам.
    5. ?????????????
    6. ПРОФИТ!!!!!!1

Я не уверен, что третий пункт можно реализовать на жаве, например. И не уверен, что он сработает в компайл-тайме.

В любом случае, вопрос какой-то странный. Наверное, в самом общем случае всё равно придётся адский манагер глобального состояния городить…

Apple-ch ★★ ()
Последнее исправление: Apple-ch (всего исправлений: 1)

педогрек опять выходит на связь

anonymous ()

Как ограничить доступ к глобальному состоянию, разрешив только определенным классам чтение/модификацию (типа friend class в c++) определенного состояния?

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

blexey ★★★★★ ()
Ответ на: комментарий от yoghurt

Можно так, да. Тогда все переменные будут иметь приватные геттеры/сеттеры и список друзей класса.
Еще можно представить задачу так (без ООПшки):

void m100500(void *state) {}
void m100501(void *state) {}

void m100499(void *state1, void *state2, ..., void stateN) {
   m100500(state1);
   m100501(state2);
   ...
   m10005000(stateN);
}

void m100498(void *state1, void *state2, ..., void stateN) {
   m100499(state1..stateN);
}

...

void m1(void *state1, void *state2, ..., void stateN) {
   if (blabla)
      m2(state1..stateN);
}

int main() {
   void *states[100500];
   InitAllStates(state1..stateN);
   m1(state1..stateN);
}
vs.
void *g_globals[100500];

void m100500() {}
void m100501() {}

void m100499() {
   m100500();
   m100501();
   ...
   m10005000();
}

void m100498() {
   m100499();
}

...

void m1() {
   if (blabla)
      m2();
}

int main() {
   InitAllStates();
   m1();
}

nerdogeek ()
Ответ на: комментарий от nerdogeek

Тогда все переменные будут иметь приватные геттеры/сеттеры и список друзей класса.

Раздели на несколько контекстов, посмотри, какие объекты у тебя что используют.

А вообще, геттеры-сеттеры, списки друзей - это всё мишура бестолковая.

yoghurt ★★★★★ ()

Как ограничить доступ к глобальному состоянию, разрешив только определенным классам чтение/модификацию (типа friend class в c++) определенного состояния? Использовать менеджер глобального состояния?

Ты же сам всё написал singleton + friend.

Ясно, что отказавшись от глобальных переменных, придется передавать их через пол-кода

Для начала реши нужно ли тебе глобальное состояние. Причины к его наличию/отсутствию - не «глобальные переменные - плохо» и не «неудобно передавать переменные через пол-кода», а глобальное ли это состояние на самом деле или нет. Подумай, может ли так статься что у тебя появится необходимость в двух разных копиях твоего состояния? Если да, то никаких глобальные переменных и синглтонов быть не должно.

причем в этом коде потом кто-то по ошибке возьмет, да и модифицирует переменную.

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

slovazap ★★★★★ ()

в той же java можно сделать package local классы, сделав к ним только геттеры и сеттеры

TERRANZ ★★★★ ()

Использовать менеджер глобального состояния?

Да. Заодно решишь проблему многопоточного доступа.

no-such-file ★★★★★ ()

Недавно встала подобная задача на php - сделать глобальный конфиг. Погуглив, наиболее красивое решение оказалось сделать синглетон с приватными членами:

class Config{
	private static $instance = NULL;
	private $params = array(
                'param1'=>'somevalue',
                'param2'=>'anothervalue',
                ...
	);

  	public function __get($var){
  		return $this->params[$var];
  	}

  	public static function getInstance(){
    	if (self::$instance == NULL){
      		self::$instance = new Config();
    	}
    	return self::$instance;
  	}	

	private function __construct(){
	}	
	private function __clone(){
	}	
}

Из любого места вызывать Config::getInstance->param1;

ИМХО все зависит от языка

IvanIvan ()

Использовать менеджер глобального состояния?

удваиваю.

nanoolinux ★★★★ ()
Ответ на: комментарий от IvanIvan

создаешь некий канал на некоей шине данных

поконкретней бы

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

В случае ТС, судя по приведенному коду ему может подойти что-то типа erlang:gen_fsm.

swwwfactory ★★ ()

изолируй, объявляй статиком. если параллельная софтина - обложи мьютексами.

про «глобальные переменные - зло» уже сказали. а вообще, все от языка зависит.

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

в ссях - я описал выше: изолировать в функцию (или набор оных) и в нутри них сделать эти переменные статическими.

Deleted ()

Риторический этот вопрос напоминает мне. Bез названия языка он. В C# я бы сделал singleton, в C++ - friend. В си - убил бы ТС.

unt1tled ★★★★ ()

А еще говорят, что монады не нужны >_>

Waterlaz ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.