Как построить структуру класса, когда члены также структурированы иерархически?
Я создаю веб-приложение PHP, которое должно предоставить пользователю возможность заказать "установку" /настройку соединения (ConnectDirect или File Transfer Gateway) между ним и другим человеком/организацией.
(Техническая спецификация реализации соединения не важна - в приложении она касается только соединений как продукта, которые можно заказать и управлять).
Иерархия классов для своего модельного слоя должна представлять собой следующую инфраструктуру реального мира:
- Есть соединения, которые можно заказать.
- Соединение может быть соединением IBM Connect: Direct или соединением шлюза IBM File Transfer.
- Соединение с компакт-диском прямо от A (источника) до B (цель).
- Соединение FTGW состоит из двух соединений: A (источник) на FTGW-сервер и от FTGW-сервера до B (target), но логически (для пользователя заказа) это также одно соединение.
- (Дополнительно есть соединение FTGW, которое использует Connect: Direct как protokoll.)
- Каждая конечная точка является либо источником, либо целью.
Итак, я вижу следующие логические элементы: логическое соединение, физическое соединение, роль (источник и цель), тип соединения, порядок, конечная точка, тип конечной точки (CD и FTGW).
Структура, которую я сейчас имеет, выглядит следующим образом:
![connections&endpoints pseudo UML class diagramm]()
Но есть некоторые проблемы:
-
Существует два дерева иерархии, где каждый элемент одного состоит из содержит элементы определенного подмножества /strong > другого (каждое соединение CD состоит из конечных точек CD, каждое соединение FTGW состоит из двух конечных точек FTGW или, что более правильно: каждое логическое соединение FTGW состоит из двух физических соединений FTGW и каждый из них состоит из конечной точки FTGW и сервер FTGW в качестве второй конечной точки).
Альтернативой может быть замена отношения между Endpoint
и PsysicalConnection
двумя отношениями: EndpointCD-PsysicalConnectionCD
и EndpointFTGW-PsysicalConnectionFTGW
.
![replaced relationships]()
Pro: более согласованный; исключает логическую неточность (или, может быть, даже ошибку) фальшивой возможности построить каждое соединение (тип) из пары любых конечных точек. Contra: на самом деле требование содержать две конечные точки является характеристикой каждого физического соединения - с этой точки зрения правильным местом для этого является самый базовый класс PsysicalConnection
.
-
Каждая конечная точка может быть и исходной и целевой, а содержит не только общие свойства конечной точки, но и источник и целевые свойства. Это означает, что в зависимости от роли конечной точки currnt некоторые свойства отходы. И это также будет влиять на структуру базы данных (столбцы, которые иногда должны быть установлены, а иногда и должны быть би NULL
).
Альтернативой является расширение иерархии...
а.... такими классами, как EndpointSource
и EndpoitTarget
, наследующими непосредственно из Endpoint
и наследуемыми классами EndpointCD
и EndpointFTGW
(что означает: два одинаковых поддеревья - под EndpointSource
и под EndpointTarget
);
б.... с помощью классов типа EndpointCDSource
и EndpointCDTarget
(наследующих от класса EndpointCD
) и EndpointFTGWSource
и EndpointFTGWTarget
(наследующих от класса EndpointFTGW
), наследуемых каждым из конкретных классов конечных точек CD или FTGW (это означает: дважды два одинаковых поддерева);
с.... классами, такими как MyConcreteEndpoint***Source
и MyConcreteEndpoint***Target
, наследующими от конкретных классов конечных точек (это означает, что каждый класс MyConcreteEndpoint
становится абстрактным и получает две подстилки - MyConcreteEndpoint***Source
и MyConcreteEndpoint***Target
, например EndpointCDLinux
) абстрактно и наследуется EndpointCDLinuxSource
и EndpointCDLinuxTarget
).
Pro: устраняет свойства отходов. Contra: более сложная иерархия классов.
Ну, это о архитектуре программного обеспечения и должно (и, конечно же, будет) быть моим дизайнерским решением. Но было бы неплохо услышать/прочитать некоторых экспертов (или неспециалистов), как справиться с таким делом. Каковы правильные способы организации логических элементов для инфраструктуры, как описано мной?
Ответы
Ответ 1
Возможно, я слишком задумываюсь, но я предлагаю вам использовать немного другую модель, чтобы отразить вашу бизнес-логику.
Следующее может быть полным недоразумением, но я дам ему шанс.
Итак:
Основываясь на том, что на самом деле какая-либо связь, вот понятие:
- Каждое соединение представляет собой набор узлов, через которые данные должны перемещаться, чтобы добраться до места назначения.
- Каждый node может подключаться со следующим node с использованием определенного протокола, который специфичен только для прямого соединения между двумя конкретными узлами.
- Протокол имеет свои собственные свойства, общие для исходных и целевых узлов.
Основываясь на этом, я предлагаю следующую модель построения, управления и хранения конфигурации продукта:
![введите описание изображения здесь]()
Здесь:
-
LogicalConnection - это ссылка на встроенную композицию фактического соединения, node и классов протокола
-
Соединение содержит двойной список узлов, которые составлены в порядке поступления данных. i.: 1-й элемент является источником node, а второй - его целью и т.д.
-
Конкретный node содержит конфигурацию для конкретной платформы, ссылку на цель (* Node), источник node (* Node) и конкретный протокол (* Протокол)
-
Протокол содержит определенную конфигурацию для источника и цели, экземпляры node могут ссылаться на экземпляр протокола для извлечения необходимой конфигурации.
-
Целевые и исходные узлы "см." конфигурация каждого другого источника и источника-источника с помощью структуры с двойными связями ".
-
Конфигурации\* Реализации ConfigBuilder организуют процесс принятия данных из пользовательского интерфейса и преобразуют его в фактический состав Connection, node и Protocol в зависимости от случая.
-
Пространства имен IBM\ConnectDirect\и IBM\FTGW\содержат конкретные реализации для протокола и * Node (например, WindowsNode, UnixNode)
Если по-прежнему существует потребность в node или в протоколе содержать как исходные, так и целевые атрибуты, а часть из них по-прежнему может быть NULL в некоторых конфигурациях - я предлагаю использовать модель хранения EAV для БД, если есть какая-либо озабоченность неиспользуемые столбцы и т.д.
Использование предлагаемых подключений модели, которые вы описали в вопросе, может быть представлено следующим образом:
Connection:IBM_CD {
nodes:[
{//LinuxNode
target:*nextElement,
protocol:{//IBM.ConnectDirect.Protocol
..target attributes..
..source attributes..
}
..platform specific attributes..
},
{//WindowsShareNode
target:*nil,
protocol:{
//IBM.ConnectDirect.Protocol(same instance or null)
}
..platform specific attributes..
},
]
}
Connection:IBM_FTGW {
nodes:[
{//LinuxNode
target:*nextElement,
source:*nil,
protocol:{//IBM.FTGW.Protocol
..target attributes..
..source attributes..
}
..platform specific attributes..
},
{//IntermediateServerLinuxNode
target:*nextElement,
source:*prevElement,
protocol:{//IBM.FTGW.Protocol
..target attributes..
..source attributes..
},
..platform specific attributes
},
{//WindowsShareNode
target:*nil,
source:*prevElement,
protocol:*nil,
..platform specific attributes..
}
]
}