策略模式

1.自定义注解

/**
 * @author Helius
 * 价格范围注解
 **/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PriceRegion {
    int min() default 0;
    int max() default Integer.MAX_VALUE;
}

2.抽象策略→策略实现

/**
 * @author Helius
 * 抽象策略
 **/
public interface Price {
    BigDecimal getPrice(BigDecimal price);
}

/**
 * @author Helius
 * 会员,六折
 **/
@PriceRegion(min = 10000, max = 20000)
class Member implements Price {
    @Override
    public BigDecimal getPrice(BigDecimal price) {
        return price.multiply(new BigDecimal(0.6 + ""));
    }
}

/**
 * @author Helius
 * 普通客户
 **/
@PriceRegion(max = 10000)
class Ordinary implements Price {
    @Override
    public BigDecimal getPrice(BigDecimal price) {
        return price;
    }
}

/**
 * @author Helius
 * 超级会员,4折
 **/
@PriceRegion(min = 20000)
class SuperMember implements Price {
    @Override
    public BigDecimal getPrice(BigDecimal price) {
        return price.multiply(new BigDecimal(0.4 + ""));
    }
}

这里可以新增其他对于价格范围的策略,也可以定义在多个文件中。

  1. 策略选择

    /**
     * 上下文
     */
    class PriceContext {
    
        BigDecimal getPrice(BigDecimal costPrice) throws Exception {
            Price price = PriceFactory.getInstance().getPrice(costPrice);
            return price.getPrice(costPrice);
        }
    }
    /**
     * @author 单例模式
     * 策略工厂
     **/
    class PriceFactory {
    
        private static final PriceFactory FACTORY = new PriceFactory();
        /**
         * 策略类集合
         */
        private List<Class<? extends Price>> priceList = new ArrayList<>();
    
    	//如果在spring环境下,可以通过实现ApplicationContextAware获取到applicationContext,遍历Price接口的实现类,添加进集合中, 降低硬编码
        private PriceFactory() {
            //这边是可以改造成自动获取文件路径的哈
            priceList.add(Member.class);
            priceList.add(Ordinary.class);
            priceList.add(SuperMember.class);
        }
    
        /**
         * 获取对应金额的策略类
         * @param price 金额
         * @return Price
         * @throws Exception classNotFound
         */
        Price getPrice(BigDecimal price) throws Exception{
            for (Class<? extends Price> clazz : priceList) {
                PriceRegion priceRegion = clazz.getAnnotation(PriceRegion.class);
                if (price.compareTo(new BigDecimal(priceRegion.max())) < 0 && price.compareTo(new BigDecimal(priceRegion.min())) > 0) {
                    return clazz.newInstance();
                }
            }
            return null;
        }
        
        static PriceFactory getInstance() {
            return FACTORY;
        }
    }
    
    

    PriceFactory是个单例类, 准确来说,这个类是个策略选择器。用于获取对应金额的策略类.

    而PriceContext则是通过PriceFactory选择出的策略类,调用getPrice()方法计算出金额。

    1. 测试类

      public class Test {
          public static void main(String[] args) throws Exception {
              PriceContext priceContext = new PriceContext();
              System.out.println(priceContext.getPrice(new BigDecimal(200)));
              System.out.println(priceContext.getPrice(new BigDecimal(11100)));
              System.out.println(priceContext.getPrice(new BigDecimal(30000)));
          }
      }
      

小结:

  • 策略模式的定义:在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
  • 代码中,主要有几下几个角色:
  • 一个接口,几个实现类,即抽象的策略,和几个真实的策略,也方便我们扩展
  • 策略选择器,也就是我们的PriceFactory,运行时根据价格选择合适的策略类,
  • priceContext只是又进一步封装了。不是重点。

比如在本例中,我们在运行时,通过传入价格,选择了不同的策略类,进行金额的计算。

  • 介绍

    意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。

    主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。

    何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。

    如何解决:将这些算法封装成一个一个的类,任意地替换。

    关键代码:实现同一个接口。

    应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。

    优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。

    缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。

    使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

    注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

上面的小结摘自网络。我觉得总结的很好。

posted @ 2019-12-23 23:41  HeliusKing  阅读(166)  评论(0编辑  收藏  举报