1、模式的定义与特点
策略(Strategy)模式:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。
策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
策略模式的主要优点:
1、多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。
2、策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
3、策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
4、策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
5、策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
缺点:
1、客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
2、策略模式造成很多的策略类。
2、模式的结构
策略模式是准备一组算法,并将这组算法封装到一系列的策略类里面,作为一个抽象策略类的子类。
策略模式的重心不是如何实现算法,而是如何组织这些算法,从而让程序结构更加灵活,具有更好的维护性和扩展性。
策略模式的主要角色:
1、抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
2、具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
3、环境(Context)类:持有一个策略类的引用,最终给客户端调用。
3、模式的应用场景
1、一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
2、一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
3、系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
4、系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
5、多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
4、模式的扩展
在一个使用策略模式的系统中,当存在的策略很多时,客户端管理所有策略算法将变得很复杂。如果在环境类中使用策略工厂模式来管理这些策略类将大大减少客户端的工作复杂度,其结构图如图2所示。
5、模式的实现
商品类:
package com.example.designpattern.strategy;
/**
* 商品类
*
* @author Administrator
* @date 2020/8/6
*/
class Product {
private String name;
private double price;
private int count;
/**
* 优惠类型
*/
private DiscountType type;
public Product(String name, double price, int count, DiscountType type) {
this.name = name;
this.price = price;
this.count = count;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public DiscountType getType() {
return type;
}
public void setType(DiscountType type) {
this.type = type;
}
}
抽象策略角色:
package com.example.designpattern.strategy;
/**
* 抽象策略角色
*
* @author Administrator
* @date 2020/8/6
*/
abstract class AbstractDiscountStrategy {
protected Product product;
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
/**
* 计算优惠
*/
public abstract double discount();
}
优惠的类型 或策略方式:
package com.example.designpattern.strategy;
/**
* 优惠的类型 或策略方式
*
* @author Administrator
* @date 2020/8/6
*/
enum DiscountType {
/**
* 无优惠
*/
NO,
/**
* 固定优惠
*/
FLATRATE,
/**
* 折扣优惠
*/
PERCENT
}
具体策略角色1:
package com.example.designpattern.strategy;
/**
* 具体策略角色
* 无优惠
*
* @author Administrator
* @date 2020/8/6
*/
class NoDiscountStrategy extends AbstractDiscountStrategy {
public NoDiscountStrategy(Product p) {
this.product = p;
}
@Override
public double discount() {
return 0;
}
}
具体策略角色2:
package com.example.designpattern.strategy;
/**
* 具体策略角色
* 固定价格优惠
*
* @author Administrator
* @date 2020/8/6
*/
class FlatrateDiscountStrategy extends AbstractDiscountStrategy {
/**
* 固定优惠数额
*/
private double flatrate;
public FlatrateDiscountStrategy(Product p, double flatrate) {
this.product = p;
this.flatrate = flatrate;
}
@Override
public double discount() {
return flatrate * product.getCount();
}
}
具体策略角色3:
package com.example.designpattern.strategy;
/**
* 具体策略角色
* 折扣优惠
*
* @author Administrator
* @date 2020/8/6
*/
class PercentDiscountStrategy extends AbstractDiscountStrategy {
/**
* 优惠的折扣
*/
private double percent;
public PercentDiscountStrategy(Product p, double percent) {
this.product = p;
this.percent = percent;
}
@Override
public double discount() {
return product.getPrice() * (1 - percent) * product.getCount();
}
}
环境角色:
package com.example.designpattern.strategy;
import java.text.DecimalFormat;
/**
* 环境角色
*
* @author Administrator
* @date 2020/8/6
*/
class Context {
private AbstractDiscountStrategy strategy;
private Product product;
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public AbstractDiscountStrategy getStrategy() {
return strategy;
}
public void setStrategy(AbstractDiscountStrategy strategy) {
this.strategy = strategy;
}
/**
* 结账
*/
public void checkout() {
String type = "";
switch (product.getType()) {
case NO:
type = "无优惠";
strategy = new NoDiscountStrategy(product);
break;
case FLATRATE:
type = "每件优惠5元";
strategy = new FlatrateDiscountStrategy(product, 5);
break;
case PERCENT:
type = "8折优惠";
strategy = new PercentDiscountStrategy(product, 0.8);
break;
default:
break;
}
//优惠价格
double discount = strategy.discount();
//保留一位小数
DecimalFormat df = new DecimalFormat("#.0");
System.out.println("商品:" + product.getName() + "\t优惠价钱:" + df.format(discount) + "\t优惠类型:" + type);
}
}
调用:
package com.example.designpattern.strategy;
/**
* @author Administrator
* @date 2020/8/6
*/
class Client {
public static void main(String[] args) {
Product p1 = new Product("玩具", 180, 1, DiscountType.NO);
Product p2 = new Product("水杯", 80, 1, DiscountType.FLATRATE);
Product p3 = new Product("毛衣", 200, 2, DiscountType.PERCENT);
Context context = new Context();
context.setProduct(p1);
context.checkout();
context.setProduct(p2);
context.checkout();
context.setProduct(p3);
context.checkout();
}
}
测试结果:
6、PPT素材
微信公众号: TechU