侧边栏壁纸
  • 累计撰写 14 篇文章
  • 累计创建 22 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

神坑面试题之策略模式

Administrator
2024-03-02 / 0 评论 / 0 点赞 / 53 阅读 / 6717 字

53c19e36beb74bb2a2d1ced548c7dc5b.png

神坑面试题之设计模式

当我看到这题目 觉得很有意思 不就是去除if else if 吗? 这不就是典型的策略模式吗?当然单独靠策略模式是无法全部消除if else if的 还需要靠工厂+策略模式 实现消除if

GOF的《设计模式》著作中认为策略模式可以消除一些条件语句,我对此持怀疑态度。正如上面的例子,虽然由于Context在初始化的时候已经指定了策略实现,在计算逻辑中不需要根据条件选择逻辑分支。但是,客户端代码在初始化Context的时候,如何判断应该传入哪个策略实现呢?其实在客户端代码或者别的地方还是缺少不了条件判断。所以这里消除条件语句,只是针对算法逻辑的条件判断。

2. 策略模式优缺点

那么策略模式的优点是什么了?

2.1 优点

  1. 使用策略模式 可以根据策略接口 定义一系列可供复用的行为和算法;
  2. 调用方只需要持有context 的引用即可 而无需知道具体策略实现 满足迪米特法则;
  3. context在策略的方法之外可以做一些通用的切面逻辑

2.2 缺点

  1. 客户端代码需要知道不同的策略以及如何选择策略。因此可以看到上面的客户端代码有着丑陋的条件判断;
  2. 由于策略类实现同样的接口,所以参数列表要保持一致,但可能并不是所有的策略都需要全部参数

3. 策略模式与工厂模式结合使用

针对第一个缺点。我们可以通过策略模式与工厂模式结合使用来改进。通过进一步封装,消除客户端代码的条件选择
代码如下

package com.zw.design.pattern.behavioral.mianshi;

/****
 * 定义一个动物类的接口 实现策略
 */
public interface IAnimalStrategy {

    public void doPromotion() ;
}
package com.zw.design.pattern.behavioral.mianshi;

/***
 * 定义一个猫的类 实现动物的接口
 */
public class CatStrategy implements IAnimalStrategy {
    @Override
    public void doPromotion() {
        System.out.println("这个是处理猫的类");
    }
}
package com.zw.design.pattern.behavioral.mianshi;

/***
 * 定义一个狗 实现动物策略接口
 */
public class DogStrategy implements IAnimalStrategy {
    @Override
    public void doPromotion() {
        System.out.println("处理dog行为");
    }
}

package com.zw.design.pattern.behavioral.mianshi;

/***
 * 定义一个空策略类 实现动物策略接口
 */
public class EmptyAnimalStrategy implements IAnimalStrategy {
    @Override
    public void doPromotion() {

    }
}

package com.zw.design.pattern.behavioral.mianshi;

/***
 * 这是pig 类实现动物策略接口类
 */
public class PigStrategy implements IAnimalStrategy {
    @Override
    public void doPromotion() {
        System.out.println("这是pig的类");
    }
}

package com.zw.design.pattern.behavioral.mianshi;

import java.util.HashMap;
import java.util.Map;
//这是一个抽象工厂 用来生产所有实现过策略模式的类
public abstract class AnimalStrategyFactory {

    //定义一个 静态的 常量的map 集合
    private final static Map<String, IAnimalStrategy> PROMOTION_STRATEGY_MAP = new HashMap<String, IAnimalStrategy>();

    //定义三个常量 并且是final 而且带分组功能
    private interface PromotionKey{
        String DOG = "dog";
        String PIG = "pig";
        String CAT = "cat";
    }


    /***
     * 根据你传入的key 返回一个具体促销的类 实现可扩展
     * @param promotionKey
     * @return
     */
    public static IAnimalStrategy getPromotionStrategy(String promotionKey){
        IAnimalStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
        // return promotionStrategy == null ? null : promotionStrategy;
        //为了业务 更友好的模式 这里不能返回null   所以定义一个无促销活动的类
        return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
    }
    //定义一个无促销的活动类
    private static final IAnimalStrategy NON_PROMOTION = new EmptyAnimalStrategy();

    //使用静态代码块进行往map 里面放入值 放入具体的策略的值
    static {
        PROMOTION_STRATEGY_MAP.put(PromotionKey.CAT,new CatStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.DOG,new DogStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.PIG,new PigStrategy());
    }
}

package com.zw.design.pattern.behavioral.mianshi;

/***
 * 使用策略模式的客户端 
 */
public class AnimalActivity {
    //放入动物策略的具体类 这里丢入接口 多态思想
    private IAnimalStrategy promotionStrategy;

    public AnimalActivity(IAnimalStrategy promotionStrategy){

        this.promotionStrategy = promotionStrategy;
    }
    //有个具体的行为
    public void executePromotionStrategy(){
        promotionStrategy.doPromotion();
    }

}
//测试
public static void main(String[] args) {
        String petType="dog";
        AnimalActivity animalActivity=new AnimalActivity(
                AnimalStrategyFactory.getPromotionStrategy(petType)
        );
        animalActivity.executePromotionStrategy();
    }

4. 策略模式适用场景

当存在多种逻辑不同,但属于同一类型的行为或者算法时,可以考虑使用策略模式。以此来消除你算法代码中的条件判断。同时让你的代码满足多种设计原则。

很多时候,工厂模式和策略模式都可以为你解决同类问题。但你要想清楚,你想要的是一个对象,还是仅仅想要一个计算结果。如果你需要的是一个对象,并且想用它做很多事情。那么请使用工厂模式。而你仅仅想要一个特定算法的计算结果,那么请使用策略模式。

策略模式属于对象行为模式,而工厂属于创建型模式。策略模式和工厂模式对比如下:

42705ad0334f4e9aaebfd9fc293cd564.png

5. 小结

策略模式解决的问题是如何封装可供复用的算法或者行为。策略模式满足了单一职责、开闭、迪米特法则、依赖倒转等原则。我们一定想清楚策略模式的适用场景,否则某些时候你会搞不清到底用工厂模式还是策略模式。最后提醒大家,设计模式很多时候都是混合使用,我们不应该局限于使用某一种设计模式来解决问题。

6.jdk和spring当中具体典型案例

jdk Comparator 比较器最佳策略模式实现
jdkTreeMap 当中 compare 方法也是策略模式的典型应用
Resource spring 当中 org.springframword.core.io 包下 当它实现类
我们可能经常用比如ClassPathResource还有文件FileSystemResource
Spring 当中Bean的初始化也是用这个类 InstantiationStrategy 它的
实现类有两个 一个是Cglib的初始化类子类
还有一个是简单的初始化策略 策略和策略之间可以存在继承关系

0
广告 广告

评论区