这是我参与 8 月更文挑战的第 6 天,活动详情查看: 8月更文挑战
策略模式
一个类的行为或算法可以在运行时改变.
实现思路
通过定义接口和实现类,来实现对一个/多个行为的的不同实现方式.
传入参数,在工厂类的map中选择需要执行的对象,返回结果
主要解决的问题
多个相似算法的情况下,使用if,else所带来的复杂和难以维护
例如有两种动物,1.如果是松鼠,那么获取他的松果的数量 2.如果是熊猫,就获取他竹子的数量
如果通过if/eles 来实现
if (type.equals("松鼠")) {
// 获取松果数量
} else if (type.equals("熊猫")) {
//获取竹子的数量
}
当有更多动物进来时,我们就要不断修改if/else 中的代码
如何通过策略模式实现呢?
public interface Animals {
int getFoodNumber();
}
//松鼠的实现方法
@Override
public int getFoodNumber() {
return songguoNum;
}
// 熊猫的实现方法
@Override
public int getFoodNumber() {
return zhuziNum;
}
使用工厂类将策略模式放入map中,然后通过传入的参数自动调用对应的行为
public class AnimalFactory {
// 用户保存策略对象
public static final Map<String, Object> map = new HashMap<>();
// 根据关键词将对象存入map中
static{
map.put("松鼠",new Songshu());
map.put("熊猫",new Panda());
}
// 根据关键词执行对应的方法.
public static int getFoodNum(String type) {
Animals animals = (Animals)map.get(type);
return animals.getFoodNumber();
}
}
执行结果
int 松果 = AnimalFactory.getFoodNum("松鼠");
System.out.println("松果"+松果);
int 竹子 = AnimalFactory.getFoodNum("熊猫");
System.out.println("竹子"+竹子);
并没有解决开放封闭原则的根本问题,虽然不需要在if/else 代码中添加判断,但是还是要创建新的策略对象并且在工厂类中将新的策略对象放入map中
使用spring原生注解来实现
1.将实现类注入容器 @Component
@Component(value = "松鼠")
public class Songshu implements Animals{
@Component(value = "熊猫")
public class Panda implements Animals{
2.改变工厂类
给map<String,Animals>添加@Autowied 注解,那么Animals接口的所有注入的实现类都会放入map中
@Component
public class NewAnimalFactory {
// // 关键功能 Spring 会自动将 EntStrategy 接口的类注入到这个Map中
@Autowired
public Map<String,Animals> map;
// 存入的值默认为bean id ,可以通过@Component(value="")来设置
public int getFoodNum(String type) {
Animals animals = map.get(type);
return animals.getFoodNumber();
}
}
3.使用
注意,1.要启动服务,不要直接main函数运行,都没有开启spring服务
2.使用@Autowied来引入工厂,不要使用new来新建工厂,都没有注入spring
@Autowired
NewAnimalFactory newAnimalFactory;
@Test
public void AnimalsTest() {
int 竹子 = newAnimalFactory.getFoodNum("熊猫");
System.out.println("竹子"+竹子);
int 松果 = newAnimalFactory.getFoodNum("松鼠");
System.out.println("松果"+松果);
}

第二种方法,使用list方法实现
相比较于map方法,list方法不需要给实现类的bean设置名称,接口新建一个方法,实现类返回一个标识符(类似于设置名称)
String typeName();
// 熊猫实现
@Override
public String typeName() {
return "熊猫";
}
// 松鼠实现
@Override
public String typeName() {
return "松鼠";
}
将实现类注入到list中,对list进行遍历比较,获得对应的数据
@Autowired
public List<Animals> animalsList;
public Animals getAnimals(String type) {
for (Animals animals:animalsList) {
if (type.equals(animals.typeName())) {
return animals;
}
}
return null;
}
执行
@Test
public void getAnimals() {
Animals 松鼠 = newAnimalFactory.getAnimals("松鼠");
System.out.println(松鼠);
Animals 熊猫 = newAnimalFactory.getAnimals("熊猫");
System.out.println(熊猫);
Animals 猴子 = newAnimalFactory.getAnimals("猴子");
System.out.println(猴子);
}

策略模式SPI实现开闭原则
直接迭代实现类,并且进行判断获得对应的对象
public static Animals getAnimals(String type) {
ServiceLoader<Animals> load = ServiceLoader.load(Animals.class);
Iterator<Animals> iterator = load.iterator();
while(iterator.hasNext()) {
Animals animals = iterator.next();
if (type.equals(animals.typeName())) {
return animals;
}
}
return null;
}
执行
public static void main(String[] args) {
Animals 松鼠 = SPIAnimalsFactory.getAnimals("松鼠");
System.out.println("松鼠:"+松鼠);
Animals 熊猫 = SPIAnimalsFactory.getAnimals("熊猫");
System.out.println("熊猫:"+熊猫);
}

优缺点
优点:1.避免多重判断 2.扩展性良好,只需要实现接口即可 3.封装内容可以自由切换
缺点:只增加一个选择,就需要增加一个新的类实现接口.