preface

Have you ever encountered a situation in development where a piece of logic starts with two branches, and you quickly use if else to do the logic, and then after a while you start happy fishing. Then your favorite product manager pops in again and again, breaks the silence, tells you that this logic has a new customer, and you have to clap if else, but you can still do it, still clap on the keyboard, and you can still feel happy.

One day, your development team leader reviews your code and gives you a love education: “This code is stinky and long. Would you like to teach it to someone else every day?”

Strategy mode, beautifying the survivability of maintainable code

What are strategic patterns

Strategy pattern is different logical clothing to different classes, and then define a strategy manager to manage the group policy and following the caller needs a strategy, simply tell strategy managers need to take a strategy will be needed, when business needs a new strategy, can add a new strategy according to the specification of strategy class, This ensures the open close principle (you can’t heap code into the current class by adding logic, it must be implemented based on extensions).

For demonstration purposes, here’s a fucking requirement for you

Now you have a requirement from your product manager. You need to build a file parsing system, and customers pass you a fileType parameter when using your system

0 A-type file 1 B-type file Other parameters Default type fileCopy the code

Then you complete their file parsing according to this parameter.

Then your dog product adds, “There may be more file parsing requirements in the future.”

Your team leader says, “Write better.”

You return group leader: “what call good look, my code font changed to boldface?”

The group leader was silent and looked at the fruit knife beside him.

You got it.

Defining a Policy Interface

Since we are going to make a file parsing module that needs to be done based on the policy pattern, we need to follow the open closed principle, so we need to define an interface that specifications all file parsing strategies.

package com.example.Strategy.config; Public interface IFileStrategy {/** * Get the file type that can be parsed by the current policy * @return */ FileTypeResolveEnum gainFileType(); @param objectParam */ void resolve(Object objectparam); }Copy the code

Use enumerations to standardize file type definitions

Your dog product says that there may be more file parsing types in the future, so in order to avoid hand-shaking logic when other developers take over your code using strings, we need to define an enumeration to ensure that the file type definition is accurate.

package com.example.Strategy.config; /** * File type enumeration */ public enum FileTypeResolveEnum {// File type A File_A_RESOLVE, // file type B File_B_RESOLVE, // Default type file File_DEFAULT_RESOLVE}Copy the code

Implement policies corresponding to various files

Next, we will complete the corresponding file parsing strategy based on the above interface

package com.example.Strategy.support; import com.alibaba.fastjson.JSON; import com.example.Strategy.config.FileTypeResolveEnum; import com.example.Strategy.config.IFileStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @component public class AFileResolve implements IFileStrategy {protected static final Logger Logger = LoggerFactory.getLogger(AFileResolve.class); @Override public FileTypeResolveEnum gainFileType() { return FileTypeResolveEnum.File_A_RESOLVE; } @override public void resolve(Object objectParam) {logger.info(" resolve A file, request parameters {}", json.tojsonString (objectParam)); }}Copy the code
package com.example.Strategy.support; import com.alibaba.fastjson.JSON; import com.example.Strategy.config.FileTypeResolveEnum; import com.example.Strategy.config.IFileStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @component public class BFileResolve implements IFileStrategy {protected static final Logger Logger = LoggerFactory.getLogger(BFileResolve.class); @Override public FileTypeResolveEnum gainFileType() { return FileTypeResolveEnum.File_B_RESOLVE; } @override public void resolve(Object objectParam) {logger.info(" resolve B file, request file {}", json.tojsonString (objectParam)); }}Copy the code
package com.example.Strategy.support; import com.alibaba.fastjson.JSON; import com.example.Strategy.config.FileTypeResolveEnum; import com.example.Strategy.config.IFileStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * @component public class DefaultFileResolve implements IFileStrategy {protected static final Logger logger = LoggerFactory.getLogger(DefaultFileResolve.class); @Override public FileTypeResolveEnum gainFileType() { return FileTypeResolveEnum.File_DEFAULT_RESOLVE; } @override public void resolve(Object objectParam) {logger.info(" resolve the default file, request parameters {}", json.tojsonString (objectParam)); }}Copy the code

A service API that exposes this set of policies

The following is the core of implementing the policy pattern. Based on Spring API, the author saves the above policies into a container of map. Subsequent callers pass the corresponding fileType parameter value, and then the author goes to map to find whether there is a corresponding policy.

package com.example.Strategy.service; import com.example.Strategy.config.FileTypeResolveEnum; import com.example.Strategy.config.IFileStrategy; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @Component public class FileResloveService implements ApplicationContextAware { private Map<FileTypeResolveEnum, IFileStrategy> iFileStrategyMap = new ConcurrentHashMap<>(); @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map<String, IFileStrategy> fileStrategyMap = applicationContext.getBeansOfType(IFileStrategy.class); fileStrategyMap.values().forEach(fileResloveObj -> iFileStrategyMap.put(fileResloveObj.gainFileType(), fileResloveObj));  } public void resolve(FileTypeResolveEnum filetype, Object objectparam) { if (iFileStrategyMap.containsKey(filetype)) { iFileStrategyMap.get(filetype).resolve(objectparam);  return; } iFileStrategyMap.get(FileTypeResolveEnum.File_DEFAULT_RESOLVE).resolve(objectparam); }}Copy the code

SetApplicationContext may be a bit unfamiliar to many readers, but spring provides us with a powerful killer. Our class simply inherits ApplicationContextAware, Spring determines if the bean is an ApplicationContextAware class when it is initialized. If so, Spring will ravage the applicationContext to you as an argument through the setApplicationContext method you inherit from ApplicationContextAware. For details, see the author’s article # Handwriting Spring Chapter 8 – Defining the Aware interface for tag types to implement Aware container objects

The test case

package com.example.Strategy.service; import com.alibaba.fastjson.JSONObject; import com.example.DesignPattern.DesignPatternApplication; import com.example.Strategy.config.FileTypeResolveEnum; import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; @RunWith(SpringRunner.class) @SpringBootTest(classes = DesignPatternApplication.class) class FileResloveServiceTest { protected static final Logger logger = LoggerFactory.getLogger(FileResloveServiceTest.class); @Resource private FileResloveService fileResloveService; @Test void resolve() { JSONObject param=new JSONObject(); Param. put(" what file "," This is type A file "); fileResloveService.resolve(FileTypeResolveEnum.File_A_RESOLVE,param); }}Copy the code

The source address

Demo code

reference

# of actual combat! Say goodbye to pipelining code and talk about common design patterns at work!