同时抽象对象和行为的模式

时间:2019-04-15 19:17:25

标签: design-patterns

我们有一个使用外部旅行系统并允许购买车票的项目。我们将票证信息保存在本地,但实际状态是在外部系统中定义的:

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);
}

现在我们还有另外两个票务系统,它们具有相同的域,对象模型并且操作流程略有不同。

我们需要抽象出具体类型FirstCorpServiceFirstCorpTicket

同时提取服务数据非常重要。具体服务无法对通用数据(票证)进行操作。要申请折扣或取消机票,您需要实际预订系统中的详细信息,具体情况视提供商而定。

当状态和算法相互对应时,是否存在可以解决所提供设计问题的设计模式?

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()。如果这一切都不成立,就没有简单的解决方案。

0 个答案:

没有答案