In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces "what are the methods to eliminate if...else". In daily operation, I believe that many people have doubts about the methods of eliminating if...else. The editor consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful to answer the doubts about "what are the methods to eliminate if...else?" Next, please follow the editor to study!
First, the smelly and long if...else
No more nonsense, let's take a look at the following code.
Public interface IPay {void pay ();} @ Service public class AliaPay implements IPay {@ Override public void pay () {System.out.println ("= initiating Alipay =");} @ Service public class WeixinPay implements IPay {@ Override public void pay () {System.out.println ("= = initiating WeChat Pay = =") } @ Service public class JingDongPay implements IPay {@ Override public void pay () {System.out.println ("= initiate JD.com pay =");} @ Service public class PayService {@ Autowired private AliaPay aliaPay; @ Autowired private WeixinPay weixinPay; @ Autowired private JingDongPay jingDongPay Public void toPay (String code) {if ("alia" .equals (code)) {aliaPay.pay ();} else if ("weixin" .equals (code)) {weixinPay.pay ();} else if ("jingdong" .equals (code)) {jingDongPay.pay () } else {System.out.println ("payment method not found");}
The toPay method of the PayService class is mainly used to initiate a payment. Depending on the code, the call is decided to use the pay method of a different payment class (for example, aliaPay) to make the payment.
What's wrong with this code? Maybe that's what some people do.
Just imagine, if there are more and more payment methods, such as Baidu pay, Meituan pay, UnionPay pay and so on, you need to change the code of the toPay method and add a new else...if judgment. More judgments will lead to more and more logic?
Obviously, it violates the six principles of design pattern: the principle of opening and closing and the principle of single responsibility.
Opening and closing principle: open for expansion and closed for modification. In other words, to add new features, you should make as few changes to the existing code as possible.
Single responsibility principle: as the name implies, the logic is required to be as simple as possible, not too complex, and easy to reuse.
Is there any way to solve this problem?
Second, the brilliant plan to eliminate if...else
1. Use annotations
The reason for using code to determine which payment class to use in the code is that code and the payment class do not have a binding relationship, and if the binding relationship exists, it does not have to be judged.
Let's define an annotation first.
Retention (RetentionPolicy.RUNTIME) @ Target (ElementType.TYPE) public @ interface PayCode {String value (); String name ();}
Add this note to all payment classes:
@ PayCode (value = "alia", name = "Alipay") @ Service public class AliaPay implements IPay {@ Override public void pay () {System.out.println ("= = initiate Alipay = =") } @ PayCode (value = "weixin", name = "WeChat Pay") @ Service public class WeixinPay implements IPay {@ Override public void pay () {System.out.println ("= = initiating WeChat Pay = =") } @ PayCode (value = "jingdong", name = "JD.com pay") @ Service public class JingDongPay implements IPay {@ Override public void pay () {System.out.println ("= = initiate JD.com pay = =");}}
Then add the most critical classes:
@ Service public class PayService2 implements ApplicationListener {private static Map payMap = null; @ Override public void onApplicationEvent (ContextRefreshedEvent contextRefreshedEvent) {ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext (); Map beansWithAnnotation = applicationContext.getBeansWithAnnotation (PayCode.class); if (beansWithAnnotation! = null) {payMap = new HashMap () BeansWithAnnotation.forEach ((key, value)-> {String bizType = value.getClass (). GetAnnotation (PayCode.class). Value (); payMap.put (bizType, (IPay) value);}} public void pay (String code) {payMap.get (code) .pay () }}
The PayService2 class implements the ApplicationListener interface so that you can get an instance of ApplicationContext in the onApplicationEvent method. Let's get the class annotated with PayCode and put it in a map. The key in map is the value defined in the PayCode annotation, which is consistent with the code parameter, and value is the instance of the payment class.
In this way, you can get the payment class instance directly through code each time, without the need for if...else judgment. If you want to add a new payment method, simply annotate the payment class with PayCode to define a new code.
Note: this way of code can have no business meaning, can be pure numbers, as long as it is not repeated.
2. Dynamic splicing name
This method is mainly aimed at scenarios where code has business implications.
@ Service public class PayService3 implements ApplicationContextAware {private ApplicationContext applicationContext; private static final String SUFFIX = "Pay"; @ Override public void setApplicationContext (ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;} public void toPay (String payCode) {((IPay) applicationContext.getBean (getBeanName (payCode) .pay () } public String getBeanName (String payCode) {return payCode + SUFFIX;}}
We can see that the name of the payment class bean is concatenated by code and suffixes, such as aliaPay, weixinPay, and jingDongPay. This requires special attention when naming the payment class, and the previous paragraph should be consistent with code. The instance of the called payment class is obtained directly from the ApplicationContext instance. By default, the bean is singleton and placed in a map in memory, so there are no performance problems.
In particular, this method implements the ApplicationContextAware interface, which is different from the ApplicationListener interface above, to tell you that there is more than one way to get ApplicationContext instances.
3. Template method judgment.
Of course, in addition to the two methods described above, the source code implementation of spring also tells us another way to solve the if...else problem.
Let's first take a look at some of the source code of spring AOP and take a look at DefaultAdvisorAdapterRegistry's wrap method.
Public Advisor wrap (Object adviceObject) throws UnknownAdviceTypeException {if (adviceObject instanceof Advisor) {return (Advisor) adviceObject;} if (! (adviceObject instanceof Advice)) {throw new UnknownAdviceTypeException (adviceObject);} Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) {return new DefaultPointcutAdvisor (advice) } for (AdvisorAdapter adapter: this.adapters) {if (adapter.supportsAdvice (advice)) {return new DefaultPointcutAdvisor (advice);}} throw new UnknownAdviceTypeException (advice);}
Focus on the supportAdvice method, which is implemented by three classes. Let's pick a random class and have a look:
Class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {@ Override public boolean supportsAdvice (Advice advice) {return (advice instanceof AfterReturningAdvice);} @ Override public MethodInterceptor getInterceptor (Advisor advisor) {AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice (); return new AfterReturningAdviceInterceptor (advice);}}
The supportsAdvice method of this class is very simple, just to determine whether the type of advice is AfterReturningAdvice.
What we see here should be enlightening.
In fact, we can do this by defining an interface or abstract class in which there is a support method to determine whether the code passed by the parameter can be handled by itself, and if so, follow the payment logic.
Public interface IPay {boolean support (String code); void pay ();} @ Service public class AliaPay implements IPay {@ Override public boolean support (String code) {return "alia" .equals (code);} @ Override public void pay () {System.out.println ("= = initiate Alipay = =") } @ Service public class WeixinPay implements IPay {@ Override public boolean support (String code) {return "weixin" .equals (code);} @ Override public void pay () {System.out.println ("= = initiating WeChat Pay = =") } @ Service public class JingDongPay implements IPay {@ Override public boolean support (String code) {return "jingdong" .equals (code);} @ Override public void pay () {System.out.println ("= = initiate JD.com pay = =");}}
Each payment class has a support method to determine whether the passed code is equal to its own definition.
Service public class PayService4 implements ApplicationContextAware, InitializingBean {private ApplicationContext applicationContext; private List payList = null; @ Override public void afterPropertiesSet () throws Exception {if (payList = = null) {payList = new ArrayList (); Map beansOfType = applicationContext.getBeansOfType (IPay.class); beansOfType.forEach ((key, value)-> payList.add (value)) } @ Override public void setApplicationContext (ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;} public void toPay (String code) {for (IPay iPay: payList) {if (iPay.support (code)) {iPay.pay () }}
In this code, the payment class instance that implements the IPay interface is initialized to a list collection, and the list collection is iterated when the payment interface is called. If the code is the same as defined by yourself, the pay method of the current payment class instance is called.
4. Strategy + factory mode
This approach is also used in scenarios where code has business implications.
The policy pattern defines a set of algorithms, encapsulates them one by one, and makes them interchangeable.
Factory pattern, which is used to encapsulate and manage the creation of objects, is a creative pattern.
Public interface IPay {void pay ();} @ Service public class AliaPay implements IPay {@ PostConstruct public void init () {PayStrategyFactory.register ("aliaPay", this);} @ Override public void pay () {System.out.println ("= = initiate Alipay = =") } @ Service public class WeixinPay implements IPay {@ PostConstruct public void init () {PayStrategyFactory.register ("weixinPay", this);} @ Override public void pay () {System.out.println ("= initiating WeChat Pay = =");} @ Service public class JingDongPay implements IPay {@ PostConstruct public void init () {PayStrategyFactory.register ("jingDongPay", this) } @ Override public void pay () {System.out.println ("= initiate JD.com pay =");}} public class PayStrategyFactory {private static Map PAY_REGISTERS = new HashMap (); public static void register (String code, IPay iPay) {if (null! = code & &! ".equals (code)) {PAY_REGISTERS.put (code, iPay) }} public static IPay get (String code) {return PAY_REGISTERS.get (code);}} @ Service public class PayService3 {public void toPay (String code) {PayStrategyFactory.get (code). Pay ();}}
The key to this code is the PayStrategyFactory class, which is a policy factory, which defines a global map, registers the current instance into map in all the implementation classes of IPay, and then obtains the payment class instance from map through the PayStrategyFactory class at the place of call.
5. Responsibility chain model
This approach is very effective in eliminating if...else when refactoring code.
Chain of responsibility pattern: the requested processing objects are combined like a long chain to form an object chain. The request does not know which specific object to execute the request, thus decoupling the request from the processing object.
The commonly used filter and spring aop use the responsibility chain mode. I have made a slight improvement here. The specific code is as follows:
Public abstract class PayHandler {@ Getter @ Setter protected PayHandler next; public abstract void pay (String pay);} @ Service public class AliaPayHandler extends PayHandler {@ Override public void pay (String code) {if ("alia" .equals (code)) {System.out.println ("= = initiate Alipay = =");} else {getNext (). Pay (code) }} @ Service public class WeixinPayHandler extends PayHandler {@ Override public void pay (String code) {if ("weixin" .equals (code)) {System.out.println ("= = launch WeChat Pay =");} else {getNext () .pay (code) } @ Service public class JingDongPayHandler extends PayHandler {@ Override public void pay (String code) {if ("jingdong" .equals (code)) {System.out.println ("= initiate JD.com payment =");} else {getNext (). Pay (code);} @ Service public class PayHandlerChain implements ApplicationContextAware, InitializingBean {private ApplicationContext applicationContext Private PayHandler header; public void handlePay (String code) {header.pay (code);} @ Override public void setApplicationContext (ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;} @ Override public void afterPropertiesSet () throws Exception {Map beansOfTypeMap = applicationContext.getBeansOfType (PayHandler.class); if (beansOfTypeMap = = null | | beansOfTypeMap.size () = 0) {return } List handlers = beansOfTypeMap.values (). Stream (). Collect (Collectors.toList ()); for (int I = 0; I
< handlers.size(); i++) { PayHandler payHandler = handlers.get(i); if (i != handlers.size() - 1) { payHandler.setNext(handlers.get(i + 1)); } } header = handlers.get(0); } } 这段代码的关键是每个PayHandler的子类,都定义了下一个需要执行的PayHandler子类,构成一个链式调用,通过PayHandlerChain把这种链式结构组装起来。 6、其他的消除if...else的方法 当然实际项目开发中使用if...else判断的场景非常多,上面只是其中几种场景。下面再列举一下,其他常见的场景。 (1)根据不同的数字返回不同的字符串 public String getMessage(int code) { if (code == 1) { return "成功"; } else if (code == -1) { return "失败"; } else if (code == -2) { return "网络超时"; } else if (code == -3) { return "参数错误"; } throw new RuntimeException("code错误"); } 其实,这种判断没有必要,用一个枚举就可以搞定。 public enum MessageEnum { SUCCESS(1, "成功"), FAIL(-1, "失败"), TIME_OUT(-2, "网络超时"), PARAM_ERROR(-3, "参数错误"); private int code; private String message; MessageEnum(int code, String message) { this.code = code; this.message = message; } public int getCode() { return this.code; } public String getMessage() { return this.message; } public static MessageEnum getMessageEnum(int code) { return Arrays.stream(MessageEnum.values()).filter(x ->X.code = = code) .findFirst () .orElse (null);}}
Then adjust the calling method slightly.
Public String getMessage (int code) {MessageEnum messageEnum = MessageEnum.getMessageEnum (code); return messageEnum.getMessage ();}
Perfect.
(2) judgment in set
The above enumeration of the getMessageEnum method in MessageEnum might be written like this if you don't use the syntax of java8
Public static MessageEnum getMessageEnum (int code) {for (MessageEnum messageEnum: MessageEnum.values ()) {if (code = = messageEnum.code) {return messageEnum;}} return null;}
For filtering data in collections, or finding methods, java8 has an easier way to eliminate if...else judgments.
Public static MessageEnum getMessageEnum (int code) {return Arrays.stream (MessageEnum.values ()) .filter (x-> x.code = = code). FindFirst (). OrElse (null);}
(3) simple judgment
In fact, there are some simple if...else that are completely unnecessary to write, and can be replaced by ternary operators, such as in this case:
Public String getMessage2 (int code) {if (code = = 1) {return "success";} return "failure";}
Change to ternary operator:
Public String getMessage2 (int code) {return code = = 1? "success": "failure";}
The code is more concise after modification.
(4) judgment in spring
For the exception of the parameter, the sooner it is found, the better. Assert is provided in spring to help us detect whether the parameter is valid.
Public void save (Integer code,String name) {if (code = = null) {throw Exception ("code cannot be empty");} else {if (name = = null) {throw Exception ("name cannot be empty");} else {System.out.println ("doSave");}
If there are too many parameters, the if...else statement will be very long, and if you use Assert class judgment instead, the code will be much simpler:
Public String save2 (Integer code,String name) {Assert.notNull (code, "code cannot be empty"); Assert.notNull (name, "name cannot be empty"); System.out.println ("doSave");} at this point, the study of "what are the ways to eliminate if...else" is over, hoping to solve everyone's doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.