如何使用策略或功能接口处理基于值(枚举)的多项选择?
How to deal with multiple choices based on value (enum) using strategy or functional interfaces?
我正在处理一个案例,我有 enum
:
public enum CurrencyType {
BTC, ETH
}
一个pojo:
public class Challenge {
private final String walletAddress;
private final CurrencyType currencyType;
//getters, constructors, setters
}
一项服务:
@Service
public ChallengeService {
public Challenge verifyMessage(final Challenge challenge) {
Challenge verifiedChallenge;
switch (challenge.getCurrencyType()) {
case BTC:
verifiedChallenge = verifyBTCMessage(challenge);
break;
case ETH:
verifiedChallenge = verifyETHMessage(challenge);
break;
default:
throw new IllegalStateException("Unexpected value: " + challenge.getCurrencyType());
}
return verifiedChallenge;
}
private Challenge verifyBTCMessage(Challenge challenge) { //implementation here }
private Challenge verifyETHMessage(Challenge challenge) { //implementation here }
}
目前枚举只包含 2 个值,ETH
和 BTC
,但有一天这个枚举中的值的数量会增加到 5、10 甚至更多。
此时我认为我的做法是错误的。我在看策略模式,它看起来不错,但似乎在某些时候我将无法逃脱整个 ifology (或 switchology 准确地说)将 Challenge
对象委托给基于 CurrencyType
枚举值的适当方法。
在阅读关于重构大师的策略模式时,我找到了这个信息(在策略模式的 cons 部分)
A lot of modern programming languages have functional type support that lets you implement different versions of an algorithm inside a set of anonymous functions.
这似乎是一种更好的方法,但是...我正处于学习函数式编程的初级阶段,老实说 - 我不知道从哪里开始。或者也许策略模式就足够了,但我遗漏了一些关键的东西?我想要实现的就是尽可能摆脱 switchology。
我想这可以按如下方式实现:
interface Verifier {
boolean isMatched(CurrencyType type);
CurrencyType currency();
Challenge verify(Challenge challenge);
}
每个具体 class 将是 used/matched 特定货币。
我建议您创建一个界面如下:
public interface MessageVerifier {
public CurrencyType handles();
public Challenge verifyMessage(Challenge challenge);
}
然后对于 BTC,你会得到类似的东西(你将对每种货币类型都有一个实现):
@Component
public class BtcMessageVerifier implements MessageVerifier {
public CurrencyType handles() {
return CurrencyType.BTC;
}
public Challenge verifyMessage(Challenge challenge) {
// Your logic here
}
}
您现在可以将所有 MessageVerifier
的列表注入 ChallengeService
并将其重新排列到一个 Map 中,以便在需要时更容易使用。
@Service
public ChallengeService {
private Map<CurrencyType, MessageVerifier> messageVerifierPerCurrency;
@Autowired
public ChallengeService(List<MessageVerifier> messageVerifiers) {
this.messageVerifierPerCurrency = messageVerifiers.stream().collect(Collectors.toMap(MessageVerifier::handles, Function.identity()));
}
public Challenge verifyMessage(final Challenge challenge) {
Challenge verifiedChallenge;
if (messageVerifierPerCurrency.containsKey(challenge.getCurrencyType())) {
verifiedChallenge = messageVerifierPerCurrency.get(challenge.getCurrencyType()).verifyMessage(challenge);
} else
throw new IllegalStateException("Unexpected value: " + challenge.getCurrencyType());
}
return verifiedChallenge;
}
}
我正在处理一个案例,我有 enum
:
public enum CurrencyType {
BTC, ETH
}
一个pojo:
public class Challenge {
private final String walletAddress;
private final CurrencyType currencyType;
//getters, constructors, setters
}
一项服务:
@Service
public ChallengeService {
public Challenge verifyMessage(final Challenge challenge) {
Challenge verifiedChallenge;
switch (challenge.getCurrencyType()) {
case BTC:
verifiedChallenge = verifyBTCMessage(challenge);
break;
case ETH:
verifiedChallenge = verifyETHMessage(challenge);
break;
default:
throw new IllegalStateException("Unexpected value: " + challenge.getCurrencyType());
}
return verifiedChallenge;
}
private Challenge verifyBTCMessage(Challenge challenge) { //implementation here }
private Challenge verifyETHMessage(Challenge challenge) { //implementation here }
}
目前枚举只包含 2 个值,ETH
和 BTC
,但有一天这个枚举中的值的数量会增加到 5、10 甚至更多。
此时我认为我的做法是错误的。我在看策略模式,它看起来不错,但似乎在某些时候我将无法逃脱整个 ifology (或 switchology 准确地说)将 Challenge
对象委托给基于 CurrencyType
枚举值的适当方法。
在阅读关于重构大师的策略模式时,我找到了这个信息(在策略模式的 cons 部分)
A lot of modern programming languages have functional type support that lets you implement different versions of an algorithm inside a set of anonymous functions.
这似乎是一种更好的方法,但是...我正处于学习函数式编程的初级阶段,老实说 - 我不知道从哪里开始。或者也许策略模式就足够了,但我遗漏了一些关键的东西?我想要实现的就是尽可能摆脱 switchology。
我想这可以按如下方式实现:
interface Verifier {
boolean isMatched(CurrencyType type);
CurrencyType currency();
Challenge verify(Challenge challenge);
}
每个具体 class 将是 used/matched 特定货币。
我建议您创建一个界面如下:
public interface MessageVerifier {
public CurrencyType handles();
public Challenge verifyMessage(Challenge challenge);
}
然后对于 BTC,你会得到类似的东西(你将对每种货币类型都有一个实现):
@Component
public class BtcMessageVerifier implements MessageVerifier {
public CurrencyType handles() {
return CurrencyType.BTC;
}
public Challenge verifyMessage(Challenge challenge) {
// Your logic here
}
}
您现在可以将所有 MessageVerifier
的列表注入 ChallengeService
并将其重新排列到一个 Map 中,以便在需要时更容易使用。
@Service
public ChallengeService {
private Map<CurrencyType, MessageVerifier> messageVerifierPerCurrency;
@Autowired
public ChallengeService(List<MessageVerifier> messageVerifiers) {
this.messageVerifierPerCurrency = messageVerifiers.stream().collect(Collectors.toMap(MessageVerifier::handles, Function.identity()));
}
public Challenge verifyMessage(final Challenge challenge) {
Challenge verifiedChallenge;
if (messageVerifierPerCurrency.containsKey(challenge.getCurrencyType())) {
verifiedChallenge = messageVerifierPerCurrency.get(challenge.getCurrencyType()).verifyMessage(challenge);
} else
throw new IllegalStateException("Unexpected value: " + challenge.getCurrencyType());
}
return verifiedChallenge;
}
}