java 设计模式-策略模式

本文章主要通过策略模式解决不同购买价格对应的不同打折方式,并通过注解达到策略的真正适配.

应用场景:

厂家为搞促销活动,推出购买的价格打折策略,具体打折如下....比如

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
 * 计算01000
 */
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 计算10002000
 */
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
 * 计算20003000
 */
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 计算10002000
 */
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
 * 计算01000
 */
@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 计算10002000
 */
@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
 * 计算20003000
 */
@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
 * 计算30004000
 */
@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));
   }
}

猜你喜欢

转载自blog.csdn.net/qq_18603599/article/details/80138165