Strategy mode may be the first mode learned by many students. This mode is really suitable as the opening mode. The main reason is that the mode is simple, pure and does not have many skills, but it well expresses the concept of design mode, so that readers can intuitively feel the benefits of design mode.
The core of policy pattern is to use polymorphism, which is supported by the mainstream object-oriented languages.
UML class diagram location: https://www.processon.com/view/link/60d29bf3e401fd49502afd25
The code link of this article is: https://github.com/shidawuhen/asap/blob/master/controller/design/20strategy.go
1. Definitions
1.1 strategy mode
Strategy mode: it defines algorithm families and encapsulates them separately so that they can be replaced with each other. This mode allows algorithm changes to not affect customers using algorithms.
UML:
1.2 analysis
The single look strategy model mainly uses polymorphism. However, the policy mode is often not used alone. It will be used together with Go design mode (7) - factory mode Use together. At this time, the policy pattern can decouple the definition, creation and use of policies.
Strategy mode processing plant mode can achieve the effect of removing if else and switch. It mainly depends on the support of plant mode and finds the specified strategy for use with the help of "look-up table method".
2. Application scenarios
The application scenarios of the policy pattern are quite extensive. If there are multiple algorithms for dealing with the same kind of problems, the policy pattern can be used. Such as calculating preferential prices according to different activities, calculating tax rates according to different types of commodities, etc.
Recently, there is an actual business scenario where the policy model can be used to calculate cross-border commodity taxes.
Taxes on cross-border goods are related to two aspects: one is whether the goods include tax; the other is the type of goods. Different types of goods have different corresponding tax rates, such as different tax rates for conventional goods and alcohol goods, and different tax calculation methods.
Therefore, you can find the corresponding calculation scheme as long as you know whether the commodity includes tax and commodity type. If we use if else to write, it will not be elegant, because there are many commodity types and the calculation logic is relatively complex, so we can use the look-up table method for optimization.
The tax calculation interface is called by the transaction side. When the transaction is called, it will be transferred to whether the commodity includes tax. The commodity type is maintained by the project team. Let's take a look at the specific implementation.
3. Code implementation
package main import "fmt" const ( Common = "COMMON" Win = "WIN" ) /** * @Author: Jason Pang * @Description: Get item type according to hscode * @param hscode * @return string */ func getProductType(hscode string) string { if hscode == "11" { return Common } else { return Win } } /** * @Author: Jason Pang * @Description: Tax calculation function, and the amount is in minutes * @param price * @param qty * @return taxPrice */ type TaxComputeFunc func(price int64, qty int64) (taxPrice int64) /** * @Author: Jason Pang * @Description: Tax calculation policy store 0 Is tax exclusive, 1 is tax inclusive */ var TaxComputeFuncMap = map[int]map[string]TaxComputeFunc{ 0: map[string]TaxComputeFunc{ Common: common, Win: win, }, 1: map[string]TaxComputeFunc{ Common: common, Win: win, }, } /** * @Author: Jason Pang * @Description: Calculate general commodity tax * @param price * @param qty * @return taxPrice */ func common(price int64, qty int64) (taxPrice int64) { radio := 0.1 fmt.Println("Calculate general commodity tax") return int64(float64(price*qty) * radio) } /** * @Author: Jason Pang * @Description: Calculation of alcohol tax * @param price * @param qty * @return taxPrice */ func win(price int64, qty int64) (taxPrice int64) { radio := 0.2 fmt.Println("Calculation of general liquor tax") return int64(float64(price*qty) * radio) } /** * @Author: Jason Pang * @Description: Calculate taxes * @param withTax * @param productType * @param price * @param qty */ func ComputeTaxPrice(withTax int, productType string, price int64, qty int64) { if taxFunc, ok := TaxComputeFuncMap[withTax][productType]; ok { taxPrice := taxFunc(price, qty) fmt.Println("Tax is", taxPrice) } else { fmt.Println("Input error, unable to calculate") } } func main() { //Get whether the commodity includes tax, commodity price, commodity quantity and commodity type withTax := 0 var price, qty int64 = 10000, 3 productType := getProductType("11") //Calculate taxes ComputeTaxPrice(withTax, productType, price, qty) }
Output:
➜ myproject go run main.go
Calculate general commodity tax
The tax is 3000
What are the benefits of writing like this? First of all, the code is very concise without a pile of judgment; Secondly, no matter adding or modifying the policy, it will not affect the main framework, that is, main\ComputeTaxPrice. Just add a new policy in TaxComputeFuncMap, which is well open to expansion. Although there are some changes to TaxComputeFuncMap, the change is small and acceptable.
If you read what I wrote before Go design mode (18) - observer mode , you will feel that the two implementations are more similar. The two are indeed similar, but there is a core difference. The observer mode calls all policies, and the policy mode accurately finds the appropriate policies to call.
summary
The strategy mode well reflects the opening and closing principle, and also shows that even a small optimization design can bring great convenience to the project development. Of course, this convenience will be fully reflected during maintenance. After all, who maintains who knows.
last
If you love my articles, you can pay attention to my official account (programmer spicy hot).
My personal blog is: https://shidawuhen.github.io/
Review of previous articles: