策略模式在学习的时候发现和工厂模式的规则非常相似,然后仔细研究了一会儿,发现了他们的一些相同点和不同点,首先看下他们的相同点。
1.都是通过继承+多态这种面向对象的思想来完成对象的创建。
2.客户端都只需要通过一个条件,就可以获得想要的对象。
3.对象的生产都是通过类似工厂类的形式来完成的。
接下来说下他们的不同点:
1.工厂模式的客户端只需要通过工厂就可以获得对象,而策略模式则中间还有一层类似配置(context)类来获取对象
2.工厂模式的客户端传入的条件即可获得对象,也仅此而已。而策略模式传入的条件更加灵活,或者说对于需要使用哪一种方式更加明确和清楚。
3.工厂模式根据条件然后通过return new的形式来获取对象,策略则是通过配置类的构造参数来完成对象的获取,传入的是整个对象,然后根据相应的参数创建相应的对象
下面是策略的简单结构图:
通过配置类里的构造方式来完成的,也就是说客户需要获得哪一种汽车只需要在配置类的构造方法里传入相应的对象即可。它和工
厂的区就像我之前看到一篇文章中所说的,工厂类似于黑盒,而策略则是白盒,简单点说就是工厂是完成对象的获取创建等一系列
过程,而策略对于要使用的对象非常的了解熟悉,他传入的是对象,也就表示对于所使用的对象熟悉程度较比工厂更高。用一个简
单的例子来说明就是,工厂模式的客户端相当于我需要一辆车,价格在20-50万之间,油耗在2.0-2.5的范围,颜色则最好是白色。
而策略模式的客户端相当于我需要一辆车,我给你一张具体的车辆配置参数图纸,你就根据这些信息给我一辆汽车。
------------------------------------------------------------------------------2020.9.15号更新---------------------------------------------------------------------
通过一个小案例来演示下,因为本人比较喜欢玩游戏 很多时候都会使用游戏来举个栗子,比如中世纪的守城战,根据不同的敌人制定不同类型的战术。
敌人类型:英格兰理查二世(狮子)
德意志沃利普伯爵(狼)
埃及国王萨拉丁(骆驼)
阿拉伯哈里发酋长(蝎子)
保加利亚领主(耗子)
正常来进行程序编写的话 通常的做法是
根据不同的类型进入不同的逻辑处理,比如type为狮心王的时候 我会定制相应的防守计划,但是随着后面敌人的类型不断增加,我就得添加新得if else。这样不利于程序得扩展,维护起来也比较麻烦,那么现在可以使用策略模式来完成,只需要3行
具体的代码如下:
1.接口
**
* 定义一个守城的接口
*/
public interface Defensive {
/**
* 不论什么敌人,都需要调用守城的方法,具体的守城方式在实现类完成
*/
void DefensiveModel();
}
2.防守每个敌人都需要继承上面的接口
/**
* 英格兰国王-理查二世(狮子心)
*/
public class Lion implements Defensive{
@Override
public void DefensiveModel() {
System.out.println("大名鼎鼎的英格兰理查二世攻城,我的防御战术是:大型防守塔增加巨弩,远程配合十字弩+重装剑士");
}
}
/**
* 埃及国王-萨拉丁仁慈者(骆驼)
*/
public class Saladin implements Defensive{
@Override
public void DefensiveModel() {
System.out.println("面对埃及国王萨拉丁的部队,我的作战计划是:使用骑兵出城攻击对方的攻城武器,在使用弓骑兵掩护,最后远程部队压制敌人");
}
}
/**
* 德意志国王-沃利普一世(野狼)
*/
public class Wolf implements Defensive{
@Override
public void DefensiveModel() {
System.out.println("野狼德意志国王沃利普一世来攻城,面对最强大的敌人,必须使用最强的防守展示来防守,我的防守战术是:射石机+巨弩等强力守城器械和十字弩+弓箭手,配合骑士+重装剑士等强力近战部队,如有必要还需增加阿拉伯雇佣兵等协同作战");
}
}
/**
* 阿拉伯酋长-哈里发(蝎子)
*/
public class Caliph implements Defensive{
@Override
public void DefensiveModel() {
System.out.println("阿拉伯酋长的部队攻城,我只需要派出弓骑兵环形射击,外加骑士冲锋和他在城外对刚即可,运用我的机动性来制胜敌军");
}
}
/**
* 保加利亚小领主-哈兰德(耗子)
*/
public class Rat implements Defensive{
@Override
public void DefensiveModel() {
System.out.println("垃圾小领主耗子来攻城,我的防御战术是:远程弓箭手+长戟兵足矣");
}
}
3.具体处理逻辑的一个类
/**
* 防守计划内容
*/
public class DefensiveContent {
/**
* 所有敌人都实现的同一个接口
*/
private Defensive defensive;
/**
* 通过构造器来对每种不同类型的敌人调用不同的作战计划
* @param defensive
*/
DefensiveContent(Defensive defensive){
this.defensive=defensive;
}
/**
* 提供一个公共的访问方式,只需要调用这个方法就可以实现不同的防守战术
*/
public void defensiveStyle(){
defensive.DefensiveModel();
}
}
4.调用测试类
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads() {
/*String type="Lion";
if("Rat".equals(type)){
Rat rat=new Rat();
rat.DefensiveModel();
}else if("Wolf".equals(type)){
Wolf wolf=new Wolf();
wolf.DefensiveModel();
}else if("Lion".equals(type)){
Lion lion=new Lion();
lion.DefensiveModel();
}else if("scorpion".equals(type)){
Caliph caliph=new Caliph();
caliph.DefensiveModel();
}else{
Saladin saladin=new Saladin();
saladin.DefensiveModel();
}*/
Defensive type=new Saladin();
DefensiveContent defensive=new DefensiveContent(type);
defensive.defensiveStyle();
}
不同的敌人传入不同类型的敌人对象到处理类里,因为所有敌人都继承了接口,具体的实现通过处理类来完成,以后只要有新的敌人,我只需要添加新的敌人实现类就行了,扩展性增加了,同时对修改关闭了,符合程序设计里的开闭原则。