设计模式——策略模式

一、引言

  十一黄金周,对于像我们这些屌丝来说,确实是个不错的出游时机,可惜的就是这个假期是public的,并不是我等屌丝独占的。真是有种生前活在人堆里的感慨,这时候选择交通工具是异常的重要,笔者回家需要经过深汕高速,每逢节假日,高速基本都会成为免费停车场的,加之国庆免费,真是雪上加霜啊。今天我所写的就是以选择交通工具为题阐述一下策略模式吧。

二、策略模式

  1. 定义:定义一组算法,将每个算法都封装起来,并使他们之间可以互换。

  2. 类图:【如下图所示】

  3. 类图说明:

    3.1 ITransport:策略抽象类,定义每个算法必须具有的方法和属性。    

    3.2 Plane,Train,Car:策略中一组算法。

    3.3 Context:上下文角色,封装算法提供客户端调用的。    

三、策略示例代码

  1. 策略抽象类

package com.pattern.stratgy.core;

/**
 * 策略接口——交通工具
 * @author yemaoan
 *
 */
public interface ITransport {
    
    void buyTicket();
}

  2. 具体策略(算法)

    2.1 选择火车

package com.pattern.stratgy.core;

public class Train implements ITransport {

    @Override
    public void buyTicket() {
        System.out.println("选择坐火车,硬座还比较划算");

    }

}

    2.2 选择飞机

package com.pattern.stratgy.core;

public class Plane implements ITransport {

    @Override
    public void buyTicket() {
        System.out.println("选择坐飞机吧,快速,便捷,关键啊,是不会塞车...");

    }

}

    2.3 选择汽车

package com.pattern.stratgy.core;

public class Car implements ITransport {

    @Override
    public void buyTicket() {
        System.out.println("选择坐汽车,堵就堵吧");

    }

}

   3. Context封装角色

package com.pattern.stratgy.core;

/**
 * 封装角色
 * @author yemaoan
 *
 */
public class Context {

    private ITransport transport;
    
    public Context(ITransport transport) {
        this.transport = transport;
    }
    
    public void buyTicket() {
        this.transport.buyTicket();
    }
}

  4. JunitTest

package com.pattern.strategy.test;

import org.junit.Test;

import com.pattern.stratgy.core.Context;
import com.pattern.stratgy.core.ITransport;
import com.pattern.stratgy.core.Train;

public class TestStrategy {

    @Test
    public void testStrage() {
        //平生就差火车,动车没坐过了,让我也过一下火车瘾吧
        ITransport transport = new Train();        //生成策略对象,这样Client就知道得太多了,不应该啊,这是病,得医~
        Context context = new Context(transport);
        context.buyTicket();
    }
}

四、策略改进方法

  其实单纯的策略模式的弊病已经在上面的代码中表现得很明显了,在客户端调用时已经把当前的策略暴露出去了,怎么解决?让工厂帮一下忙吧,让我们看一下下面的一段代码。

  1. 策略工厂

package com.pattern.stategy.factory;

import com.pattern.stratgy.core.ITransport;

/**
 * 设计模式老朋友了——策略工厂类
 * @author yemaoan
 *
 */
public class StrategyFactory {

    public static <T extends ITransport> T getTransport(Class<T> cls) {
        ITransport transport = null;
        try {
            transport = (ITransport) Class.forName(cls.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return (T) transport;
    }
    
    public static <T extends ITransport> T getTransport(String code) {
        return (T) getTransport(new ContentService().get(code));
    }
}

  2. 算法值映射类

package com.pattern.stategy.factory;

import java.util.HashMap;
import java.util.Map;

import com.pattern.stratgy.core.Car;
import com.pattern.stratgy.core.Plane;
import com.pattern.stratgy.core.Train;

/**
 * 算法映射
 * @author yemaoan
 *
 */
public class ContentService {

    private Map<String, Class> contentMap = new HashMap<String, Class>();
    
    public ContentService() {
        contentMap.put("train", Train.class);
        contentMap.put("plane", Plane.class);
        contentMap.put("car", Car.class);
    }
    
    public Class get(String key) {
        return contentMap.get(key);
    }
}

  3. JunitTest【Client】

package com.pattern.strategy.test;

import org.junit.Test;

import com.pattern.stategy.factory.StrategyFactory;
import com.pattern.stratgy.core.Context;
import com.pattern.stratgy.core.ITransport;
import com.pattern.stratgy.core.Train;

public class TestStrategy {

    @Test
    public void testStrage() {
        //平生就差火车,动车没坐过了,让我也过一下火车瘾吧
        ITransport transport = new Train();        //生成策略对象,这样Client就知道得太多了,不应该啊,这是病,得医~
        Context context = new Context(transport);
        context.buyTicket();
    }
    
    @Test
    public void testStrategy() {
        ITransport transport = StrategyFactory.getTransport("train");    //让工厂模式帮了我一把
        Context context = new Context(transport);
        context.buyTicket();
    }
}

五、总结

  1. 本文是对策略模式的一个阐述,策略其实也算是一个比较好理解的模式吧。当然单纯的使用策略模式是不太现实的,因为它会把算法完全的暴露给调用者,兵家之大忌啊。

  2. 针对策略模式的一些不足,笔者采用了工厂模式去解决,使得客户端调用时,只需要根据特定的code来获取相应的算法策略,而避免直接new算法策略。

原文地址:https://www.cnblogs.com/maoan/p/3352891.html