У меня есть эта проблема, где я должен разработать пакет Java, который используется для:
Прямо сейчас я делаю его при наличии булева значения в Классе A и Классе B, указывающем, существует ли ошибка и другой объект для хранения фактического сообщения об ошибке. Вызывающая сторона должна будет проверить это булево значение после звонка, чтобы видеть, произошла ли ошибка.
Что такое хорошая модель дизайна для этого?
Ответ был бы очень широким, поэтому я бы предложил вам использовать объект доступа:
Этот код PSuedo имеет аналогичный синтаксис как UML и Python :
// The data implements one interface
Data {interface}
// And you implement it with DatabaseData
DbData -> Data
...
// Or WebServiceData
WsData -> Data
...
// -- DAO part
Dao {interface}
+ fetch(): Data[]
// From database
DatabaseDao -> Dao
- data: Data[0..*]
// Query database and create dbData from rows...
+ fetch(): Data[]
self.status = "Not ok"
self.status = connectToDb()
if( self.status == ok ,
performQuery()
forEach( row in resultSet,
data.add( DbData.new( resultSet.next() ) )
)
disconnect()
)
...
// From web service
WebServiceDao -> Dao
- data: Data[0..*]
// Execute remote method and create wsData from some strange object
+ fetch(): Data[]
remoteObject: SoapObject = SoapObject()
remoteObject.connect()
if (remoteObject.connected?(),
differentData: StrangeObject = remoteObject.getRemoteData()
forEach( object in differentData ,
self.data.add( WsData.new( fromElement ))
)
).else(
self.status = "Disconnected"
)
....
// -- State part
// Abstract the way the data is going to be retrieved
// either from two sources or from a single one.
FetcheState { abstract }
- context: Service
- dao: Dao // Used for a single source
+ doFetch(): Data[] { abstract }
+ setContext( context: Service )
self.context = context
+ setSingleSource( dao: Dao)
self.dao = dao
// Fetches only from one DAO, and it doesn't quite merge anything
// because there is only one source after all.
OneSourceState -> FetcheState
// Use the single DAO and fetch
+ doFetch(): Data[]
data: Data[] = self.dao.doFetch()
// It doesn't hurt to call "context's" merger anyway.
context.merger.merge( data, null )
// Two sources, are more complex, fetches both DAOs, and validates error.
// If one source had an error, it changes the "state" of the application (context),
// so it can fetch from single source next time.
TwoSourcesState -> FetcheState
- db: Dao = DatabaseDao.new()
- ws: Dao = WebServiceDao.new()
+ doFetch(): Data[]
dbData: Data[] = db.doFetch()
wsData: Data[] = ws.doFetch()
if( ws.hadError() or db.hadError(),
// Changes the context's state
context.fetcher = OneSourceState.new()
context.merger = OneKindMergeStrategy.new()
context.fetcher.setContext( self.context )
// Find out which one was broken
if( ws.hadError(),
context.fetcher.setSingleSource( db )
)
if( db.hadError(),
context.fetcher.setSingleSource( ws )
)
)
// Since we have the data already let's
// merge it with the "context's" merger.
return context.merger.merge( dbData, wsData)
// -- Strategy part --
// Encapsulate algoritm to merge data
Strategy{ interface }
+ merge( a: Data[], with : Data[] )
// One kind doesn't merge too much, just "cast" one array
// because there is only one source after all.
OneKindMergeStrategy -> Strategy
+ merge( a: Data[], b: Data[] )
mergedData: Data[]
forEach( item, in( a ),
mergedData = Data.new( item ) // Take values from wsData or dbData
)
return mergedData
// Two kinds merge, encapsulate the complex algorithm to
// merge data from two sources.
TwoKindsMergeStrategy -> Strategy
+ merge( a: Data[], with: Data[] ): Data[]
forEach( item, in( a ),
mergedData: Data[]
forEach( other, in(with ),
WsData wsData = WsData.cast( item )
DbData dbData = DbData.cast( other )
// Add strange and complex logic here.
newItem = Data.new()
if( wsData.name == dbData.column.name and etc. etc ,
newItem.name = wsData+dbData...e tc. etc
...
mergedData.add( newItem )
)
)
)
return mergedData
// Finally, the service where the actual fetch is being performed.
Service { facade }
- merger: Strategy
- fetcher: FetcheState
// Initialise the object with the default "strategy" and the default "state".
+ init()
self.fetcher = TwoSourcesState()
self.merger = TwoKindsMergeStrategy()
fetcher.setContext( self )
// Nahh, just let the state do its work.
+ doFetch(): Data[]
// Fetch using the current application state
return fetcher.doFetch()
Использование клиента:
service: Service = Service.new()
service.init()
data: Data[] = service.doFetch()
К сожалению, он выглядит немного сложно.
OOP основано на полиморфизме.
Итак, в DAO
, вы позволяете данным подкласса из любого места, и вы просто называете это dao.fetch ().
В стратегия
то же самое, подкласс выполняет один алгоритм или другой (чтобы избежать много странного , если
, else
, Переключатель
и т. Д.).
С состоянием
то же самое происходит. Вместо того, чтобы идти как:
if isBroken and itDoesntWork() and if ImAlive()
и т. Д., И т. Д. Вы просто говорите: «Эй, это будет код один. Есть два соединения, и это, когда есть только один».
Наконец, фасад говорит клиенту «Не волнуйся, я справимся с этим».
Вам необходимо написать решение или Вам нужно решение? Есть много бесплатного программного обеспечения Java, которое делает эти вещи - зачем восстанавливать колесо. См.:
Я бы предложил бы фасад, который будет представлять объект в целом (данные клиента) и фабрику, который создает этот объект, извлекивая из каждого источника данных и передаю их на фасаду (в конструкторе или в качестве строителя, в зависимости от На сколько есть). Отдельный класс с конкретным источником данных будет иметь метод (на общий интерфейс или базовый класс), чтобы указать, что произошла ошибка, извлекая данные. Фасад (или делегат) будет нести ответственность за объединение данных.
Тогда фасад будет иметь метод, который вернет сборку своего рода, указывающую, какие источники данных представлен объект, или какие из них не удалось - в зависимости от того, что клиент должен знать.