我们有一个使用外部旅行系统并允许购买车票的项目。我们将票证信息保存在本地,但实际状态是在外部系统中定义的:
FirstCorpService srv1 = new FirstCorpService();
FirstCorpTicket tkt1 = srv1.buyTicket(...);
tktEntity1 = ticketRepository.save(CorpCode.CORP1, tkt1.getId(), Status.NEW);
...
srv1.applyDiscount(tkt1);
...
tktEntity1 = ticketRepository.findById(id);
FirstCorpTicket tkt1 = srv1.loadTicket(tktEntity1.getExternalId());
if ( ! tkt1.isCancelled()) {
srv1.cancel(tkt1);
tktEntity1.setStatus(State.CANCELLED);
ticketRepository.save(tktEntity1);
}
现在我们还有另外两个票务系统,它们具有相同的域,对象模型并且操作流程略有不同。
我们需要抽象出具体类型FirstCorpService
和FirstCorpTicket
。
同时提取服务和数据非常重要。具体服务无法对通用数据(票证)进行操作。要申请折扣或取消机票,您需要实际预订系统中的详细信息,具体情况视提供商而定。
当状态和算法相互对应时,是否存在可以解决所提供设计问题的设计模式?
TL; DR 为了使实现提供者不可知,我考虑对包装了 service 和 data 的对象使用多态。在以下实施设计中可能违反了SOLID / GRASP,这就是为什么我寻求帮助。
抽象客票操作:
interface TicketI {
long getId();
void applyDiscount();
boolean isCancelled();
void cancel();
}
由于典型的OOP语言不支持new
运算符的多态性,因此我们需要工厂为具体票据创建包装器:
interface TicketFactoryI {
TicketI buy(...);
TicketI load(long externalId);
}
具体的工厂和票务代表工作:
interface Corp2TicketWrapper implements TicketI {
Corp2Service srv;
Corp2Ticket tkt;
constructor(Corp2Service srv, Corp2Ticket tkt) {
this.srv = srv;
this.tkt = tkt;
}
long getId() { return tkt.getId(); }
boolean isCancelled() { return tkt.isCancelled(); }
void applyDiscount() {
srv.applyDiscount(tkt);
}
void cancel() {
srv.cancel(tkt);
}
}
class Corp2TicketFactory implements TicketFactoryI {
Corp2Service srv;
TicketI buy(...) {
Corp2Ticket tkt = srv.buyTicket(...);
return new Corp2TicketWrapper(srv, tkt);
}
TicketI load(long externalId) {
Corp2Ticket tkt = srv.loadTicket(externalId);
return new Corp2TicketWrapper(srv, tkt);
}
}
根据CorpCode.CORP1
/ CorpCode.CORP2
等,我们可以提供工厂工厂,这将是实施分派的唯一场所:
class TicketFactoryFactory {
static getInstance(CorpCode corporationCode) {
switch (corporationCode) {
case CorpCode.CORP1: return new Corp1TicketFactory();
case CorpCode.CORP2: return new Corp2TicketFactory();
case CorpCode.CORP3: return new Corp3TicketFactory();
}
}
}
原始程序不会引用具体的供应商代码:
TicketFactoryI tktFactory = TicketFactoryFactory.getInstance(CorpCode.CORP2);
TicketI tkt = tktFactory.buyTicket(...);
tktEntity = ticketRepository.save(CorpCode.CORP2, tkt.getId(), Status.NEW);
...
tkt.applyDiscount();
...
tktEntity = ticketRepository.findById(id);
TicketI tkt = tktFactory.load(tktEntity.getExternalId());
if ( ! tkt.isCancelled()) {
tkt.cancel();
tktEntity.setStatus(State.CANCELLED);
ticketRepository.save(tktEntity);
}
更新来自https://stackoverflow.com/a/670337/173149
这是OOD中的经典问题。如果一组类(动物)是固定的,则可以使用访客模式。如果您的一组操作(例如feed)受到限制,则只需向Animal添加方法feed()。如果这一切都不成立,就没有简单的解决方案。