【问题标题】:Implement strategy pattern with enum使用枚举实现策略模式
【发布时间】:2020-05-31 22:12:02
【问题描述】:

我正在尝试创建一项服务来处理不同的付款方式。我想实施策略模式。我想要一个具有不同付款方式的枚举。这是我所拥有的一个例子:

public enum Pay {
    CREDITCARD(1) {
        @Override
        public void pay() {
            System.out.println("Payment functionality");
        }

    },
    OTHERMETHOD(2) {
        @Override
        public void pay() {
            System.out.println("Payment functionality");
        }
    };

    private int id;

    Payment(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public abstract void pay();
}

在客户端某处:

user.setPay(Pay.CREDITCARD);
user.pay();

这种方法的问题是“支付”方法可能有很多逻辑,所以我想把它放在不同的类中。我可以定义这样的接口:

public interface Pay {
    void pay();
}

public class CreditCard implements Pay {
    @Override
    public void pay() {
    }
}

public class OtherMethod implements Pay {
    @Override
    public void pay() {
    }
}

在客户端某处:

if (method.equals("creditcard")) {
    user.setPay(new CreditCard());
    user.pay();
}
else {
    user.setPay(new OtherMethod());
    user.pay();
}

但我更喜欢 Enum 的外观以及保持这种方式的原因。谢谢

【问题讨论】:

  • 那不是Pay,那是PaymentMethod。显然有不同的信用卡,毕竟我的名字和你的不同。当您致电setPay() 然后使用pay() 时,情况会变得更糟。试试setPaymentMethod() - 你会发现pay 也不能只用一种支付方式,你需要一张实际的卡。 ID 本身没有意义,已经有一个ordinal() 方法。如果你在课堂设计的早期犯了这样的错误,那么当你深陷其中时,将很难追溯。

标签: java design-patterns


【解决方案1】:

我不建议在枚举中实现逻辑,因为您可能需要调用外部服务来实现支付,因此您希望能够在支付实现中注入这些依赖项。枚举是静态初始化的,它们对注入一点也不友好。可以将一些逻辑放入枚举中,尽管它们通常应该在很大程度上保持简单数据,但这种情况似乎过于复杂,无法在枚举中处理。您可以有一个枚举来决定支付的类型,然后根据需要将每个枚举项映射到一个支付实现的单例,但逻辑应该与枚举解耦。

【讨论】:

    【解决方案2】:

    您不需要客户端中的 if 语句。如果您使用Pay(接口)类型的参数声明 set Pay,您可以通过每个实现 Pay 接口的类来调用它。你的代码变成了

    user.setPay(new CreditCard()); //or every class which implements Pya interface
    user.pay();
    

    枚举在这种情况下是无用的。如果你想给每个支付方式一个数字id,把它添加到接口中。

    【讨论】:

    • 需要使用 If 语句来决定使用哪种策略。这是无法避免的。
    【解决方案3】:

    可以这样开发

    public enum PayType {
       CREDITCARD(new CreditCard()),
       OTHER(new OtherMethod();
    
       private Pay pay;
       PayType(Pay pay) {
          this.pay = pay;
       }
    
    }
    

    【讨论】: