本文章主要通过策略模式解决不同购买价格对应的不同打折方式,并通过注解达到策略的真正适配.
应用场景:
厂家为搞促销活动,推出购买的价格打折策略,具体打折如下....比如
0-1000,不打折
1001-2000打九折
2001-3000打八折
3001-4000打七折
解决方案:策略模式
因为策略模式就是解决在不同算法之间的动态切换。
具体代码如下:
package app.four.strategy; /** * @author 18011618 * 定义计算价格的策略接口 */ public abstract class AbstractCalPriceStrategy { public abstract double calPrice(double orgnicPrice); }
各种价格实现的策略:
计算0-1000
package app.four.strategy.impl; import app.four.annoation.PriceRange; import app.four.strategy.AbstractCalPriceStrategy; /** * @author 18011618 * 计算0到1000 */ public class OneQPriceStrategy extends AbstractCalPriceStrategy{ /** * 真实的业务场景,可能还有很多其他逻辑需要处理 * @param orgnicPrice * @return */ @Override public double calPrice(double orgnicPrice) { return orgnicPrice; } }
计算1001-2000
package app.four.strategy.impl; import app.four.annoation.PriceRange; import app.four.strategy.AbstractCalPriceStrategy; /** * @author 18011618 计算1000到2000 */ public class TwoQPriceStrategy extends AbstractCalPriceStrategy { /** * 真实的业务场景,可能还有很多其他逻辑需要处理 * @param orgnicPrice * @return */ @Override public double calPrice(double orgnicPrice) { return orgnicPrice * 0.8; } }
计算2001-3000
package app.four.strategy.impl; import app.four.annoation.PriceRange; import app.four.strategy.AbstractCalPriceStrategy; /** * @author 18011618 * 计算2000到3000 */ public class ThirdQPriceStrategy extends AbstractCalPriceStrategy { /** * 真实的业务场景,可能还有很多其他逻辑需要处理 * @param orgnicPrice * @return */ @Override public double calPrice(double orgnicPrice) { return orgnicPrice * 0.7; } }
计算3001-4000
package app.four.strategy.impl; import app.four.annoation.PriceRange; import app.four.strategy.AbstractCalPriceStrategy; /** * @author 18011618 计算1000到2000 */ public class TwoQPriceStrategy extends AbstractCalPriceStrategy { /** * 真实的业务场景,可能还有很多其他逻辑需要处理 * @param orgnicPrice * @return */ @Override public double calPrice(double orgnicPrice) { return orgnicPrice * 0.8; } }
使用策略模式,往往要结合简单工厂,封装具体策略根据条件,策略工厂代码如下:
package app.four.factory; import app.four.strategy.AbstractCalPriceStrategy; import app.four.strategy.impl.FourQPriceStrategy; import app.four.strategy.impl.OneQPriceStrategy; import app.four.strategy.impl.ThirdQPriceStrategy; import app.four.strategy.impl.TwoQPriceStrategy; /** * @author 18011618 * */ public class PriceStrategyFactory { /** * 根据不同的购买架构选择不同的策略实例 * @param money * @return */ public static AbstractCalPriceStrategy getCalPriceStrategy(double money){ AbstractCalPriceStrategy strategy = null; if (money>0 && money<1000) { strategy = new OneQPriceStrategy(); } else if (money>1000 && money<2000) { strategy = new TwoQPriceStrategy(); } else if (money>2000 && money<3000) { strategy = new ThirdQPriceStrategy(); } else if (money>3000 && money<4000) { strategy = new FourQPriceStrategy(); } return strategy; } }
为了让客户端和具体的策略解耦,使用策略上下文来进行封装,策略上下文代码如下:
package app.four.context; import app.four.factory.PriceStrategyFactory; import app.four.strategy.AbstractCalPriceStrategy; /** * @author 18011618 * 封装策略上下文 */ public class PriceStrategyContext { private AbstractCalPriceStrategy strategy; public double calcPrice(double money){ strategy = PriceStrategyFactory.getCalPriceStrategy(money); return strategy.calPrice(money); } }
客户端演示类:
package app.four.client; import app.four.context.PriceStrategyContext; /** * @author 18011618 * */ public class PriceMain { public static void main(String[] args) { System.out.println("============打印价格计算信息==============="); PriceStrategyContext context = new PriceStrategyContext(); double price = context.calcPrice(900); System.out.println("非会员,购买价格为900,打折之后的价格:"+price); double price1 = context.calcPrice(1500); System.out.println("普通会员,购买价格为1500,打折之后的价格:"+price1); double price2 = context.calcPrice(2300); System.out.println("vip会员,购买价格为2300,打折之后的价格:"+price2); double price3 = context.calcPrice(3200); System.out.println("超级会员,购买价格为3200,打折之后的价格:"+price3); } }
扩展计算方式,很简单只需要加上一个对应的策略实现,然后再在策略工厂里面加一个判断就可以了,但是如果每加一个策略就要修改工厂,这样是违反了开闭原则,那么有没有更好的方法了,接下来我们就对模式进行升级,通过使用注解来控制策略的自动适配.
因为打折是根据用户购买的价格区间来的,所以我们只需要获取价格的最小值和最大值,然后选择对应的计算策略来实现就可以了.
首先定义价格区间范围注解类:
package app.four.annoation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author 18011618 * 价格区间范围 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface PriceRange { int maxPrice();//价格最大值 int minPrice();//价格最小值 }
现在我们需要在每种策略加上对应计算注解范围
0-1000策略注解
package app.four.strategy.impl; import app.four.annoation.PriceRange; import app.four.strategy.AbstractCalPriceStrategy; /** * @author 18011618 * 计算0到1000 */ @PriceRange(minPrice=0,maxPrice=1000) public class OneQPriceStrategy extends AbstractCalPriceStrategy{ /** * 真实的业务场景,可能还有很多其他逻辑需要处理 * @param orgnicPrice * @return */ @Override public double calPrice(double orgnicPrice) { return orgnicPrice; } }
1001-2000策略注解
package app.four.strategy.impl; import app.four.annoation.PriceRange; import app.four.strategy.AbstractCalPriceStrategy; /** * @author 18011618 计算1000到2000 */ @PriceRange(minPrice=1001,maxPrice=2000) public class TwoQPriceStrategy extends AbstractCalPriceStrategy { /** * 真实的业务场景,可能还有很多其他逻辑需要处理 * @param orgnicPrice * @return */ @Override public double calPrice(double orgnicPrice) { return orgnicPrice * 0.8; } }
2001-3000策略注解
package app.four.strategy.impl; import app.four.annoation.PriceRange; import app.four.strategy.AbstractCalPriceStrategy; /** * @author 18011618 * 计算2000到3000 */ @PriceRange(minPrice=2001,maxPrice=3000) public class ThirdQPriceStrategy extends AbstractCalPriceStrategy { /** * 真实的业务场景,可能还有很多其他逻辑需要处理 * @param orgnicPrice * @return */ @Override public double calPrice(double orgnicPrice) { return orgnicPrice * 0.7; } }
3001-4000策略注解
package app.four.strategy.impl; import app.four.annoation.PriceRange; import app.four.strategy.AbstractCalPriceStrategy; /** * @author 18011618 * 计算3000到4000 */ @PriceRange(minPrice=3001,maxPrice=4000) public class FourQPriceStrategy extends AbstractCalPriceStrategy { /** * 真实的业务场景,可能还有很多其他逻辑需要处理 * @param orgnicPrice * @return */ @Override public double calPrice(double orgnicPrice) { return orgnicPrice * 0.6; } }
接下来需要通过解析注解,获取到各种价格对应的具体计算策略,注解解析策略工厂代码如下:
package app.four.factory; import java.io.File; import java.io.FileFilter; import java.io.ObjectInputStream.GetField; import java.lang.annotation.Annotation; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import app.four.annoation.PriceRange; import app.four.strategy.AbstractCalPriceStrategy; /** * @author 18011618 * 通过注解自动适配策略 */ @SuppressWarnings("all") public class AnnoationStrategyFactory { //策略实现类的包路径 private static final String CAL_PRICE_PACKAGE = "app.four.strategy.impl"; private ClassLoader classLoader = this.getClass().getClassLoader(); private List<Class<? extends AbstractCalPriceStrategy>> priceStrategyList; /** * 获取策略注解范围 * @param clazz * @return */ private PriceRange getPriceRange(Class<? extends AbstractCalPriceStrategy> clazz){ Annotation[] annoations = clazz.getDeclaredAnnotations(); if (annoations==null || annoations.length==0) { return null; } return (PriceRange)annoations[0]; } /** * 获取类资源文件 * @return */ private File[] getResources() { try { File file = new File(classLoader.getResource(CAL_PRICE_PACKAGE.replace(".", "/")).toURI()); return file.listFiles(new FileFilter() { public boolean accept(File pathname) { if (pathname.getName().endsWith(".class")) { return true; } return false; } }); } catch (URISyntaxException e) { throw new RuntimeException("加载资源策略接口失败"); } } /** * 加载策略计算类型 */ private void loadStrategyClsInstance(){ priceStrategyList = new ArrayList<Class<? extends AbstractCalPriceStrategy>>(); File[]files = getResources(); Class<? extends AbstractCalPriceStrategy>strategyClazz = null; try { strategyClazz = (Class<? extends AbstractCalPriceStrategy>) classLoader.loadClass(AbstractCalPriceStrategy.class.getName()); } catch (ClassNotFoundException e) { throw new RuntimeException("查找策略计算接口失败"); } for (int i = 0; i < files.length; i++) { try { Class<?> clazz = classLoader.loadClass(CAL_PRICE_PACKAGE + "."+ files[i].getName().replace(".class", "")); if (AbstractCalPriceStrategy.class.isAssignableFrom(clazz)&& clazz!=strategyClazz) { priceStrategyList.add((Class<? extends AbstractCalPriceStrategy>) clazz); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } } /** * 获取计算策略适配 * @param money * @return */ public AbstractCalPriceStrategy getStrategyInstance(double money){ AbstractCalPriceStrategy strategy = null; if (priceStrategyList!=null && priceStrategyList.size()>0) { for(Class<? extends AbstractCalPriceStrategy> clazz:priceStrategyList){ PriceRange range = this.getPriceRange(clazz); double minPrice = range.minPrice(); double maxPrice = range.maxPrice(); if(money>=minPrice && money<=maxPrice){ try { return clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } } } return strategy; } /** * 通过内部类实现单例 */ private AnnoationStrategyFactory(){ loadStrategyClsInstance(); } private static class InnerStrategy{ static AnnoationStrategyFactory instance = new AnnoationStrategyFactory(); } public static AnnoationStrategyFactory getStrategyFactory(){ return InnerStrategy.instance; } }
策略封装上下文
package app.four.context; import app.four.factory.AnnoationStrategyFactory; import app.four.factory.PriceStrategyFactory; import app.four.strategy.AbstractCalPriceStrategy; /** * @author 18011618 * 封装策略上下文 */ public class AnnoationPriceStrategyContext { private AbstractCalPriceStrategy strategy; public double calcPrice(double money){ strategy = AnnoationStrategyFactory.getStrategyFactory().getStrategyInstance(money); return strategy.calPrice(money); } }
策略计算演示:
package app.four.client; import app.four.context.AnnoationPriceStrategyContext; /** * @author 18011618 * 通过注解 */ public class PriceAnnoationMain { public static void main(String[] args) { int money =3050; AnnoationPriceStrategyContext strategy = new AnnoationPriceStrategyContext(); System.out.println(strategy.calcPrice(money)); } }