Java 杂谈程序员技术栈Java知识书屋

设计模式之策略模式(七)

2019-03-28  本文已影响5人  3d0829501918

策略模式就是定义一系列的算法,把它们的一个个封装起来,并且使它们可以相互替换,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()));

         }
}

小结:

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


适用场景

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

作用

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

重点

 策略模式体现了开闭原则:策略模式把一系列的可变算法进行封装,从而定义了良好的程序结构,在出现新的算法的时候,可以很容易的将新的算法实现加入到已有的系统中,而已有的实现不需要修改。
 策略模式体现了里氏替换原则:策略模式是一个扁平的结构,各个策略实现都是兄弟关系,实现了同一个接口或者继承了同一个抽象类。这样只要使用策略的客户端保持面向抽象编程,就可以动态的切换不同的策略实现以进行替换。


注意啦! 往期文章目录在这里


上一篇 下一篇

猜你喜欢

热点阅读