简体   繁体   中英

Implement strategy pattern with enum

I'm trying to create a service to handle different payment methods. I want to implement strategy pattern. I'd like to have an enum with the different payment methods. This is an example of what I have:

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

somewhere in the client:

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

The problem with this approach is that method "pay" could be have a lot of logic so I'd like to have it in a different class. I could define an interface like this:

public interface Pay {
    void pay();
}

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

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

somewhere in the client:

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

but I like much more how it looks with Enum and that the reason to keep that way. Thanks

I don't recommend implementing the logic inside an enum because you will likely need to make calls to external services to implement a payment, and therefore you'll want to be able to inject those dependencies in your payment implementations. Enums being statically initialized, they are not friendly at all for injection. It can be ok to put some logic in enumerations, although they should generally largely remain simple data, but this case seems too complex for being handled in enums. You can have an enum to decide the type of payment and then have a mapping from each enum item to a singleton of a payment implementations if you want, but the logic should be decoupled from the enum.

You don't need the if statement in the client. If you declare set Pay with a parameter of type Pay (the interface), you can invoke it passing every class which implements the Pay interface. Your code becames

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

The enum is useless in this case. If you want to give to each payment methods a numerical id, add it to the interface.

It can be developed like this

public enum PayType {
   CREDITCARD(new CreditCard()),
   OTHER(new OtherMethod();

   private Pay pay;
   PayType(Pay pay) {
      this.pay = pay;
   }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM