策略模式主要解决代码中分支语句过多的问题,可以满足开发中的扩展性和隔离性,策略模式是一种行为模式,应用于策略与实际场景解耦情况。
1、策略模式类图
2、框架中策略模式应用
Comparable,内部比较器
package com.hongyan.strategy;
public interface Comparable<T> {
int compareTo(T o);
}
package com.hongyan.strategy;
public class Cat implements Comparable<Cat> {
int weight, height;
public Cat(int weight, int height) {
this.weight = weight;
this.height = height;
}
public int compareTo(Cat c) {
return Integer.compare(this.weight, c.weight);
}
@Override
public String toString() {
return "Cat{" +
"weight=" + weight +
", height=" + height +
'}';
}
}
package com.hongyan.strategy;
public class Sorter1 {
public void sort(Cat[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minPos = i;
for (int j = i + 1; j < arr.length; j++) {
minPos = arr[j].compareTo(arr[minPos]) == -1 ? j : minPos;
}
swap(arr, i, minPos);
}
}
void swap(Cat[] arr, int i, int j) {
Cat temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
package com.hongyan.strategy;
import java.util.Arrays;
public class Main1 {
public static void main(String[] args) {
Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
Sorter1 sorter = new Sorter1();
sorter.sort(a);
System.out.println(Arrays.toString(a));
}
}
// 根据weight排序
result:[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
Comparator外部比较器
package com.hongyan.strategy;
public class Cat {
int weight, height;
public Cat(int weight, int height) {
this.weight = weight;
this.height = height;
}
@Override
public String toString() {
return "Cat{" +
"weight=" + weight +
", height=" + height +
'}';
}
}
package com.hongyan.strategy;
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
package com.hongyan.strategy;
public class CatWeightComparator implements Comparator<Cat> {
@Override
public int compare(Cat o1, Cat o2) {
return Integer.compare(o1.weight, o2.weight);
}
}
package com.hongyan.strategy;
public class Sorter<T> {
public void sort(T[] arr, Comparator<T> comparator) {
for (int i = 0; i < arr.length - 1; i++) {
int minPos = i;
for (int j = i + 1; j < arr.length; j++) {
minPos = comparator.compare(arr[j], arr[minPos]) == -1 ? j : minPos;
}
swap(arr, i, minPos);
}
}
void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
package com.hongyan.strategy;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
Cat[] a1 = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
Sorter<Cat> sorter = new Sorter<>();
// 通过 lambada 表达式方式实现不同的排序策略
sorter.sort(a, (o1, o2)-> Integer.compare(o1.weight, o2.weight));
System.out.println(Arrays.toString(a));
// 通过实现 Comparator 接口实现不同的排序策略
sorter.sort(a1, new CatWeightComparator());
System.out.println(Arrays.toString(a1));
}
}
//两种方式结果一致
[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
线程池中的异常处理也是策略模式的体现
3、业务中策略模式应用
package cn.bugstack.design;
import java.math.BigDecimal;
/**
* <p>
* 优惠券折扣计算接口
* <p>
* 优惠券类型;
* 1. 直减券
* 2. 满减券
* 3. 折扣券
* 4. n元购
*/
public interface ICouponDiscount<T> {
/**
* 优惠券金额计算
* @param couponInfo 券折扣信息;直减、满减、折扣、N元购
* @param skuPrice sku金额
* @return 优惠后金额
*/
BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice);
}
package cn.bugstack.design.impl;
import cn.bugstack.design.ICouponDiscount;
import java.math.BigDecimal;
import java.util.Map;
/**
* 满减
*/
public class MJCouponDiscount implements ICouponDiscount<Map<String,String>> {
/**
* 满减计算
* 1. 判断满足x元后-n元,否则不减
* 2. 最低支付金额1元
*/
public BigDecimal discountAmount(Map<String,String> couponInfo, BigDecimal skuPrice) {
String x = couponInfo.get("x");
String o = couponInfo.get("n");
// 小于商品金额条件的,直接返回商品原价
if (skuPrice.compareTo(new BigDecimal(x)) < 0) return skuPrice;
// 减去优惠金额判断
BigDecimal discountAmount = skuPrice.subtract(new BigDecimal(o));
if (discountAmount.compareTo(BigDecimal.ZERO) < 1) return BigDecimal.ONE;
return discountAmount;
}
}
package cn.bugstack.design.impl;
import cn.bugstack.design.ICouponDiscount;
import java.math.BigDecimal;
/**
* n元购买
*/
public class NYGCouponDiscount implements ICouponDiscount<Double> {
/**
* n元购购买
* 1. 无论原价多少钱都固定金额购买
*/
public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {
return new BigDecimal(couponInfo);
}
}
package cn.bugstack.design.impl;
import cn.bugstack.design.ICouponDiscount;
import java.math.BigDecimal;
/**
* 直减
*/
public class ZJCouponDiscount implements ICouponDiscount<Double> {
/**
* 直减计算
* 1. 使用商品价格减去优惠价格
* 2. 最低支付金额1元
*/
public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {
BigDecimal discountAmount = skuPrice.subtract(new BigDecimal(couponInfo));
if (discountAmount.compareTo(BigDecimal.ZERO) < 1) return BigDecimal.ONE;
return discountAmount;
}
}
package cn.bugstack.design.impl;
import cn.bugstack.design.ICouponDiscount;
import java.math.BigDecimal;
/**
* 折扣
*/
public class ZKCouponDiscount implements ICouponDiscount<Double> {
/**
* 折扣计算
* 1. 使用商品价格乘以折扣比例,为最后支付金额
* 2. 保留两位小数
* 3. 最低支付金额1元
*/
public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {
BigDecimal discountAmount = skuPrice.multiply(new BigDecimal(couponInfo)).setScale(2, BigDecimal.ROUND_HALF_UP);
if (discountAmount.compareTo(BigDecimal.ZERO) < 1) return BigDecimal.ONE;
return discountAmount;
}
}
package cn.bugstack.design;
import java.math.BigDecimal;
public class Context<T> {
private ICouponDiscount<T> couponDiscount;
public Context(ICouponDiscount<T> couponDiscount) {
this.couponDiscount = couponDiscount;
}
public BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice) {
return couponDiscount.discountAmount(couponInfo, skuPrice);
}
}
package cn.bugstack.design.test;
import cn.bugstack.design.Context;
import cn.bugstack.design.impl.MJCouponDiscount;
import cn.bugstack.design.impl.NYGCouponDiscount;
import cn.bugstack.design.impl.ZJCouponDiscount;
import cn.bugstack.design.impl.ZKCouponDiscount;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
/**
* 测试
*/
public class ApiTest {
private Logger logger = LoggerFactory.getLogger(ApiTest.class);
@Test
public void test_zj() {
// 直减;100-10,商品100元
Context<Double> context = new Context<Double>(new ZJCouponDiscount());
BigDecimal discountAmount = context.discountAmount(10D, new BigDecimal(100));
logger.info("测试结果:直减优惠后金额 {}", discountAmount);
}
@Test
public void test_mj() {
// 满100减10,商品100元
Context<Map<String,String>> context = new Context<Map<String,String>>(new MJCouponDiscount());
Map<String,String> mapReq = new HashMap<String, String>();
mapReq.put("x","100");
mapReq.put("n","10");
BigDecimal discountAmount = context.discountAmount(mapReq, new BigDecimal(100));
logger.info("测试结果:满减优惠后金额 {}", discountAmount);
}
@Test
public void test_zk() {
// 折扣9折,商品100元
Context<Double> context = new Context<Double>(new ZKCouponDiscount());
BigDecimal discountAmount = context.discountAmount(0.9D, new BigDecimal(100));
logger.info("测试结果:折扣9折后金额 {}", discountAmount);
}
@Test
public void test_nyg() {
// n元购;100-10,商品100元
Context<Double> context = new Context<Double>(new NYGCouponDiscount());
BigDecimal discountAmount = context.discountAmount(90D, new BigDecimal(100));
logger.info("测试结果:n元购优惠后金额 {}", discountAmount);
}
}
模式需要灵活运用,切记让模式限制住自己的设计想法。