设计模式-策略模式

策略模式就是定义一系列的算法,把它们的一个个封装起来,并且使它们可以相互替换,Strategy模式使算法独立于使用它的客户而变化。

策略模式组成

抽象策略角色(Strategy)

通常用一个抽象类或者接口来实现,主要定义这个算法所完成的功能。

具体策略角色(ConcreteStrategy)

包装了相关的算法和行为。

环境角色(Context)

持有策略类的引用。

策略模式特点

一种行为模式,对算法封装,使得客户端独立于各个策略,扩展性强,添加策略无非就是添加一个具体的实现类而已,代价非常低。

例子

抽象策略角色

public interface Operation {
      public double  op(double a, double b);
}

添加4个具体策略角色类Add、Sub、Multi、Div

public class Add implements Operation {

       @Override
       public double op(double a, double b) {
              double result = a + b;
              return result;
        }
}
public class Sub implements  Operation {
     @Override
     public double op(double a, double b) {
            double result = a-b;
            return result;
     }
}
public class Multi  implements  Operation {
    @Override
    public double op(double a, double b) {
           double result = a*b;
        return result;
    }
}
 public class Div  implements  Operation {
    @Override
    public double op(double a, double b) {
           double result = a/b;
        return result;
    }
}

环境角色

public class Calc {
      public static  final  Add add = new Add();
      public static  final  Sub sub = new Sub();
      public static  final  Div div = new Div();
      public static  final  Multi multi = new Multi();
}

测试类

public class Test {

    public static void main (String[] args) {
          Calc calc = new Calc();
          double add =   calc.add.op(11,22);
          double sub =  calc.sub.op(22,11);
          double div = calc.div.op(33,11);
          double multi = calc.multi.op(33,33);
          System.out.println(add);
          System.out.println(sub);
          System.out.println(div);
          System.out.println(multi);
     }
}

测试结果

 33.0
 11.0
 3.0
 1089.0

策略模式优缺点

优点

提供管理相关算法的办法,避免使用多重的条件判断语句。扩展性更好,在策略模式中扩展策略实现非常的容易,只要新增一个策略实现类,然后在使用策略实现的地方,使用这个新的策略实现就好了。

缺点

客户端必须知道所有的策略类,自己决定使用哪一个策略类,造成很多的策略类。

小例子

假设现在要设计一个贩卖各类书籍的电子商务的购物车(Shopping Cat) 系统。一个最简单的情况就是把所有货品的单价乘上数量,但是实际上肯定比这要复杂。 

会有哪些情况呢?

可能对所有的儿童类图书实行每本图书实现1元的折扣

计算类图书提供每本7%的促销折扣,而对电子类图书有3%的折扣,其余图书没有折扣

还会有新的折扣策略,由于这样复杂的折扣算法,使得价格计算问题需要系统地解决。

方式一

public abstract class Book {
       // 价格
       private double price;
       // 书名称
       private String name;
       // 定义计算折扣的变量
       public abstract double getSalePrice();
       // 省略set()get()方法
}

儿童图书类

public class ChildrenBook extends  Book {

       public ChildrenBook (String name,double price) {
              this.setName(name);
              this.setPrice(price);
       }

       @Override
       public double getSalePrice() {
              return this.getPrice() -1;
       }
}

计算机类

public class CsBook extends Book {

    public CsBook (String name,double price) {
           this.setName(name);
           this.setPrice(price);
     }

     @Override
     public double getSalePrice() {
          return this.getPrice() * 0.7;
     }
}

测试类

public class Client {

    public static void main(String[] args) {
         // 方式一  在实现抽象类方法,在子类进行各自实现打折算法,即使打折算法相同。也要重写。
         Book book = new CsBook("Think in java",45);
         Book childrenBook = new ChildrenBook("安徒生的故事",20);
         System.out.println("Think in java原价:"+book.getPrice() +"打折价:"+book.getSalePrice());
         System.out.println("安徒生的故事原价:"+childrenBook.getPrice() +"打折价:"+childrenBook.getSalePrice());
   }
}

小结:

每个子类必须都各自实现打折算法,即使打折算法相同。

方式二

public abstract class Book {

       private double price;

       private String name;
       // 把打折策略代码提到父类来实现
       public static double toSalePrice (Book book) {
              double result = 0;
             if (book instanceof  ChildrenBook) {
                  result = book.getPrice() - 1;
             } else if (book instanceof  CsBook) {
                  result = book.getPrice() * 0.7;
             } else {
                  result = 0;
             }
              return result;
        }
}

测试类

public class Client {

        public static void main(String[] args) {
            Book book = new CsBook("Think in java",45);
            Book childrenBook = new ChildrenBook("安徒生的故事",20);
           System.out.println("Think in java原价:"+book.getPrice() +"打折价:"+ Book.toSalePrice(book));
           System.out.println("安徒生的故事原价:"+childrenBook.getPrice() +"打折价:"+ Book.toSalePrice(childrenBook));
        }
}

小结:

如果策略模式复杂用if判断比较乱,并且策略修改或怎加是需要改变原代码。

策略模式

抽象策略角色

public interface BookInterface {

       public double dissCount(double price);
}

具体实现角色(计算机图书类)

public class CalculationBook implements  BookInterface {

@Override
public double dissCount(double price) {
    double result = price * 0.7;
    return result;
}
}

具体实现角色(儿童图书类)

public class ChildrenBook implements  BookInterface {
@Override
public double dissCount(double price) {
    double result = price - 1;
    return result;
}
}

环境角色

public class DiscountStrategy {

    public final static CalculationBook book = new CalculationBook();
    public final static ChildrenBook childrenBook = new ChildrenBook();
}

在Book类添加折扣策略类

public abstract class Book {

      private double price;

      private String name;

      public abstract double getSalePrice();
      // 折扣策略
      private DiscountStrategy discountStrategy;
}

测试类

public class Client {

        public static void main(String[] args) {
            Book book = new CsBook("Think in java",45);
            Book childrenBook = new ChildrenBook("安徒生的故事",20);
            System.out.println("Think in java原价:"+book.getPrice() +"打折价:"+ book.getDiscountStrategy().book.dissCount(book.getPrice()));
            System.out.println("安徒生的故事原价:"+childrenBook.getPrice() +"打折价:"+ book.getDiscountStrategy().childrenBook.dissCount(childrenBook.getPrice()));

         }
}

小结:

使用策略模式更加灵活,可以任意增加具体角色类。

深入理解策略模式

适用场景

系统有很多类,而他们区别仅仅在与它们的行为,动态选择几种算法中的一种,一个对象有很多行为。

作用

就是把具体的算法实现从业务逻辑中剥离出来,成为一系列独立算法类,使得它们可以相互替换。

重点

策略模式体现了开闭原则:策略模式把一系列的可变算法进行封装,从而定义了良好的程序结构,在出现新的算法的时候,可以很容易的将新的算法实现加入到已有的系统中,而已有的实现不需要修改。

策略模式体现了里氏替换原则:策略模式是一个扁平的结构,各个策略实现都是兄弟关系,实现了同一个接口或者继承了同一个抽象类。这样只要使用策略的客户端保持面向抽象编程,就可以动态的切换不同的策略实现以进行替换。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值