У меня есть ценность, которая нужна многим объектам. Например, финансовое приложение с различными инвестициями в качестве объектов, и большинству из них нужна текущая процентная ставка.
Я надеялся инкапсулировать свою «финансовую среду» как объект, с процентной ставкой как собственность. Но родственные объекты, которым нужно это значение, не могут добраться до него.
Итак, как я могу поделиться значениями между многими объектами, не перегружая мой дизайн? Очевидно, я думаю об этом неправильно.
object-oriented
Greg
источник
источник
update
функции, которая вызывается на каждом временном шаге? Можете ли вы написать в псевдокоде, как работает ваша симуляция?Singleton
глобальный с синтаксическим сахаром OO и ужасным решением, которое тесно связывает ваш код некоторыми из худших возможных способов. Читайте эту статью снова и снова, пока не поймете это!DateTime
качестве входных данных и возвращает число в качестве выходных данных.Ответы:
Это дизайнерский запах. Нередко многим объектам нужно что-то знать. Тем не менее, текущая процентная ставка является довольно хорошим примером исключительных обстоятельств. Одна вещь , чтобы беспокоиться о том , что редко процентная ставка. Различные финансовые инструменты используют разные ставки. По крайней мере, в разных регионах используются разные «стандартные» тарифы. Кроме того, чтобы помочь в тестировании и составлении отчетов, вы, как правило, захотите сдать курс, поскольку вы не хотите использовать текущий тариф там. Вы хотите использовать ставку «что, если» или «на отчетную дату».
Разделяя их, не заставляя их всех ссылаться на один экземпляр. Передача одной и той же вещи по-прежнему связана со степенью, но не со связью, поскольку что-то вроде текущей процентной ставки необходимо в качестве входных данных для различных вычислений.
источник
В этом конкретном случае я бы использовал шаблон Singleton . FinancialEnvironment будет объектом, о котором знают все другие библиотеки классов, но будет создан экземпляром Singleton. В идеале вы должны отправить этот экземпляр объекта в различные библиотеки классов.
Например:
Другие классы связаны только через библиотеку классов Entities, они принимают экземпляр объекта FinancialEnvironment. Они не заботятся о том, как он был создан, только сервисный уровень, все, что им нужно, это информация. Синглтон также может быть достаточно умен для хранения нескольких объектов FinancialEnvironment, в зависимости от локальных правил, как указал @Telastyn.
С другой стороны, я не большой поклонник Singleton Pattern, я считаю его запахом кода, поскольку его очень легко неправильно использовать. Но в некоторых случаях вам это нужно.
Обновить:
Если вам абсолютно необходимо иметь глобальную переменную, то реализация шаблона Singleton, как описано выше, будет работать. Тем не менее, я не большой поклонник этого, и, судя по комментариям из моего исходного поста, некоторые другие люди тоже не являются. Будучи чем-то столь же изменчивым, как InterestRate, синглтон может быть не лучшим решением. Синглтоны работают лучше всего, когда информация не меняется. Например, я использовал Singleton в одном из своих приложений для создания экземпляров счетчиков производительности. Потому что, если они меняются, у вас должна быть логика для обработки обновляемых данных.
Если бы я был букмекером, я бы поспорил, что процентная ставка была сохранена где-то в базе данных или была получена через веб-сервис. В этом случае для получения этой информации будет рекомендовано хранилище (уровень доступа к данным). Чтобы избежать ненужных посещений базы данных (я не уверен, как часто меняются процентные ставки или другая информация в классе FinancialInformation), можно использовать кэширование. В мире C # библиотека Microsoft Caching Application Block работает очень хорошо.
Единственное, что могло бы измениться из приведенного выше примера, - это различные классы в слое обслуживания, которые нуждаются в извлечении финансовой информации из уровня доступа к данным вместо создания экземпляра объекта Singleton.
источник
Singleton
является глобальным с синтаксическим сахаром OO и опорой для ленивых и слабоумных.Singleton/global
это самый худший способ тесно связать ваш код с чем-то, что потом станет раком, когда вы поймете, какая это колоссально плохая идея и почему все так говорят!Файлы конфигурации?
Если у вас есть значения, которые используются «глобально», поместите их в файл конфигурации. Затем каждая система и подсистема могут ссылаться на это и извлекать необходимые ключи, делая их доступными только для чтения.
источник
Я говорю об опыте одного из тех, у кого есть месяц поддержки проекта хорошего размера (~ 50k LOC), который мы только что выпустили.
Я могу сказать вам, что вы, вероятно, не хотите глобального объекта. Внедрение такого рода беспорядков дает гораздо больше возможностей для злоупотреблений, чем помогает.
Мое первоначальное предложение состоит в том, что если у вас есть несколько разных классов, которым нужна текущая процентная ставка, то вы, вероятно, захотите, чтобы они реализовали
IInterestRateConsumer
или что-то в этом роде. Внутри этого интерфейса вы будете иметьSetCurrentInterestRate(double rate)
(или то, что имеет смысл), или, может быть, просто свойство.Распространение процентной ставки на самом деле не является связующим звеном - если вашему классу нужна процентная ставка, это часть его API. Это только сцепление, если один из ваших классов начинает беспокоиться о том, как именно другой класс использует эту процентную ставку.
источник
У Мартина Фаулера есть статья, в которой кратко рассказывается о том, как преобразовать статический глобал в нечто более гибкое. По сути, вы превращаете его в одноэлементный, затем изменяете одноэлементный, чтобы он поддерживал переопределение класса экземпляра с помощью подкласса (и при необходимости перемещаете логику, которая создает экземпляр, в отдельный класс, который можно разделить на подклассы, что вы должны сделать если при создании экземпляра суперкласса возникает проблема с его последующей заменой).
Конечно, вы должны взвесить проблемы с синглетонами (даже заменяемыми синглетонами) и боль от прохождения одного и того же объекта повсюду.
Что касается объекта «финансовая среда» - это удобно для программирования на первом проходе, но когда вы закончите, вы добавили некоторые дополнительные зависимости. Классы, которым нужна только процентная ставка, теперь функционируют только при передаче объекта финансовой среды, что затруднит их повторное использование, когда у вас не окажется объекта финансовой среды. Так что я бы не рекомендовал широко его распространять.
источник
Почему бы не поместить данные о процентной ставке в центральный кеш?
Вы можете использовать одну из нескольких библиотек кеша, в зависимости от того, что вам больше подходит, что-то вроде memcached решит все ваши проблемы параллелизма и управления кодом и позволит вашему приложению масштабироваться до нескольких процессов.
Или перейдите к целиком и сохраните их в базе данных, которая позволит вам масштабироваться до нескольких серверов.
источник
В таких ситуациях я успешно ввел (повторно использовал) термин «контекст», иногда с несколькими слоями.
Это означает одноэлементное, то есть «глобальное» хранилище объектов, из которого могут быть запрошены объекты такого типа. Коды, которые требуют их, включают в себя заголовок хранилища и используют глобальные функции для получения экземпляров своих объектов (как, например, поставщик процентных ставок).
Магазин может быть:
Чем больше система, тем более пригодно последнее решение для довольно небольшого риска использования неправильного перечисления. С другой стороны, с языками, которые допускают прямое объявление типов, я думаю, что вы можете использовать типизированные средства доступа без включения всех заголовков в хранилище.
Еще одно примечание: у вас может быть несколько экземпляров одного и того же типа объекта для разных целей, например, иногда разные значения языка для графического интерфейса пользователя, а также для журналов распечатки, глобального уровня и журнала сеанса и т. Д., Поэтому имя перечисления / средства доступа НЕ должно отражать фактический тип , но роль запрошенного экземпляра (CurrentInterestRate).
В реализации магазина вы должны управлять уровнями контекста и коллекциями экземпляров контекста. Простым примером является веб-служба, где у вас есть глобальный контекст (один экземпляр для всех запросов для этого объекта - проблемный при наличии фермы серверов) и контекст для каждого веб-сеанса. Вы также можете иметь контексты для каждого пользователя, который может иметь несколько параллельных сессий и т. Д. С несколькими серверами вы должны использовать своего рода распределенный кеш для таких вещей.
Когда приходит запрос, вы решаете, на каком уровне контекста находится запрошенный объект, получите этот контекст для вызова. Если объект есть, вы отправляете его обратно; если нет, вы создаете и сохраняете его на этом уровне контекста и возвращаете его. Конечно, синхронизировать раздел создания (и опубликовать его в распределенном кеше). Создание может быть настраиваемым, как плагин, лучше всего с языками, позволяющими создавать экземпляры объектов по имени их класса (Java, Objective C, ...), но вы можете сделать это и в C с подключаемыми библиотеками, имеющими фабричные функции.
Примечание: вызывающий объект НЕ должен знать слишком много о своих собственных контекстах и уровне контекста запрашиваемого объекта. Причины: 1: легко допустить ошибку (или «умные трюки»), играя с этими параметрами; 2: уровень контекста запрошенного может измениться позже. Я в основном подключаю контекстную информацию к потоку, поэтому хранилище объектов содержит информацию без дополнительных параметров из запроса.
С другой стороны, запрос может содержать подсказку для экземпляра: например, получение процентной ставки на определенную дату. Это должен быть один и тот же «глобальный» доступ, но несколько экземпляров в зависимости от даты (и приведение разных значений даты к одному и тому же экземпляру между изменениями курса), поэтому рекомендуется добавить в запрос объект «подсказка», используемый экземпляр фабрики а не магазина; и keyForHint для фабрики, используемой магазином. Вы можете добавить эти функции позже, я только что упомянул.
В вашем случае это является своего рода излишним (на глобальном уровне обслуживается только один объект), но для совсем небольшого и простого дополнительного кода прямо сейчас вы получаете механизм для дальнейших, возможно, более сложных требований.
Еще одна хорошая новость: если вы находитесь на Java, вы получаете этот сервис от Spring, не задумываясь, я просто хотел объяснить это подробнее.
источник
Причина, по которой НЕ используется глобальный (или синглтонный) код, заключается в том, что даже если изначально вы ожидаете иметь только одно значение, часто удивительно полезно иметь возможность использовать один и тот же код несколько раз в одной и той же программе, например:
Я бы сделал процентную ставку членом класса «финансовых инструментов» и согласился бы с тем, что вам необходимо передать ее любым классам участников (либо на расчёт, либо на указатель / привязку к нему при создании).
источник
Вещи должны передаваться в сообщениях, а не читаться из глобальной вещи.
источник