`

设计模式--策略模式

阅读更多

 


策略模式

        定义:定义了算法族,分别将他们封装起来,让它们之间能相互替换。此模式让算法独立于使用算法的用户。

 类图


 

下面我们用两个列子来说明策略模式的实际用途。

1. 从上班开始

有一个程序员类,他有一个名称,然后有一个上班的方法:



 代码如下:

 

 

//程序员类
public class Programmer {
    //姓名
    private String name;
    //getter & setter
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //  构造方法
    public Programmer(String name) {
        this.name = name;
    }
    //上班的方法
    public void GoToWork(){
        System.out.println("坐地铁上班!"); 
    }
}

 如果,我们的同事上班方式有所不同,有的人坐地铁,有的人做公交车,有的人骑自行车…那么这个类明显不能满足我们的要求,怎么办?有的人想到了继承,就是创造一个坐公交的程序员,让那些坐公交的人继承程序员类,然后重写GoToWork()方法,这个方法是解决了问题,可是我们想想,如果程序员有任何变化,增加或者修改某个属性或者方法,那么就得对子类进行修改,这是一个不能接受的结果?有更优雅的方式吗?有的人想到了接口,就是将上班抽象成接口,然后让不同上班方式去继承接口,再让他们继承程序员类,并且去实现上班接口



 这样是将上班行为分离出来了,但是如果增加了步行上班的人、开车上班的人…..等等,代码越来越多了,而且总是要去继承程序员类,实现上班接口,而且有一天,哪个坐地铁的人买了车,改为开车上班呢?是不是的去改代码?没法动态改变?还有没有更优越的方式呢?

是的,用策略模式~!就是将上班的方式改为一个接口,并且以组合的方式放在程序员的内部,然后让各种上班方式去实现这个上班的接口,程序员上班时,动态传入上班的工具,调用接口中的上班方法就可以了。程序员类不需要知道通过什么方式上班,上班的人自己确定通过哪种方式上班就行了:

 



  //上班接口

public interface GoToWork {
    void goToWork(String name);
}

 //坐地铁上班

public class SubwayToWork implements GoToWork {
//  坐地铁上班
    public void goToWork(String name) {
        System.out.println(name + "坐地铁上班");
    }
}
 

 

//坐公交上班
public class BusToWork implements GoToWork {
    public void goToWork(String name) {
        System.out.println(name + "坐公交上班");
    }
}

 //开车上班

public class DriveToWork implements GoToWork {
    public void goToWork(String name) {
        System.out.println(name + "开车上班");
    }
}

 //程序员类

public class Programmer {
    //姓名
    private String name;
    //将上班方法变成一个接口
    private GoToWork goToWork;
    //  构造方法
    public Programmer(GoToWork goToWork) {
        this.goToWork = goToWork;
    }
    //上班的方法
    public void goToWork(String name){
        goToWork.goToWork(name);
    }
    //getter & setter
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public GoToWork getGoToWork() {
        return goToWork;
    }
    public void setGoToWork(GoToWork goToWork) {
        this.goToWork = goToWork;
    }
}

 //测试程序员上班

public class ProgrammerTest {
    public static void main(String[] args) {
        //坐地铁上班方式上班
        SubwayToWork subway = new SubwayToWork();
        Programmer p = new Programmer(subway);
        p.goToWork("小明");
//      坐公交上班方式上班
        BusToWork bus = new BusToWork();
        p.setGoToWork(bus);
        p.goToWork("小红");
//      有一天小明买车了
        DriveToWork drive = new DriveToWork();
        p.setGoToWork(drive);
        p.goToWork("小明");
    }
}

 如果哪天增加了一个骑自行车上班的人,那么,只需要去继承GoToWork接口,实现goToWork方法,就行了,不需要改动程序员类,程序员类也不用知道有没有骑自行车上班这个方法。充分解耦了程序员类与上班方式之间的关系。

这里引出了几个设计原则:
1. 解耦:我个人认为就是将变化的部分分离出来,想想,如果我们把这几种上班方式都放在一个类里会怎么样:


 

2. 针对接口编程:我们只需要针对上班方式这个接口编程,不需要去修改程序员类。

再举第二个例子:商场收银系统,收银除了计算商品单价、数量和总价外,有时候要做活动,比如:打八折、打五折,满500送减200等等。我们就拿单个商品来说:(因为真正的商场收费系统还比较复杂,因为要计算每一种商品的价格,数量,折扣,而且还要计算总价的折扣方式,商品和商场都有各自的折扣方式)


 

//结账类
public class CheckOut {
    private Commodity commodity; //商品
    private String discount; //折扣方式
    //构造方法
    public CheckOut(Commodity commodity,String discount) {
        this.commodity = commodity;
        this.discount = discount;
    }
    //结账方法
    public double checkOut(){
        if(this.discount.equals("打八折")){
            return this.commodity.total() * 0.8;
        }else if(this.discount.equals("打五折")){
            return this.commodity.total() * 0.5;
        }else if(this.discount.equals("满500减200")){
            int i = (int)this.commodity.total()/500;
            return (this.commodity.total() - (i * 200));
        }else{
            return 0;
        }
    }
    //getter & setter
    public Commodity getCommodity() {
        return commodity;
    }
    public void setCommodity(Commodity commodity) {
        this.commodity = commodity;
    }
    public String getDiscount() {
        return discount;
    }
    public void setDiscount(String discount) {
        this.discount = discount;
    }
}
 

 

//商品类
public class Commodity {
    //价格
    private double price;
    //数量
    private double quantity;
    //总价
    public double total(){
        return this.price * this.quantity;
    }
    //getter & setter
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public double getQuantity() {
        return quantity;
    }
    public void setQuantity(double quantity) {
        this.quantity = quantity;
    }
}
 

 

//测试结账
public class CheckOutTest {
    public static void main(String[] args) {
//        商品类
        Commodity c = new Commodity();
        c.setPrice(500);
        c.setQuantity(3);
//        根据购买的商品进行结账
        CheckOut checkOut = new CheckOut(c, "满500减200");
        System.out.println("您需要付:"+ checkOut.checkOut());
    }
}
 

 

看到这段代码,然后想想之前的代码,根据设计的原则,也该将结账类中的checkOut结账打折方法独立出来,这是变化的部分,结账也该和打折分开。我们收款时,只需要传入相关的策略,就能得到对应的结果。

我们先看看类图 


 

 

//结账类
public class CheckOut {
    //收银接口
    private MakeCollection makeCollection;
    //Commodity
    private Commodity commodity;
    //构造方法
    public CheckOut(MakeCollection makeCollection,Commodity commodity) {
        this.makeCollection = makeCollection;
        this.commodity = commodity;
    }
    //结账方法
    public double makeCollection(){
        return makeCollection.makecollection(commodity);
    }
    //getter  & setter
    public Commodity getCommodity() {
        return commodity;
    }
    public void setCommodity(Commodity commodity) {
        this.commodity = commodity;
    }
    public MakeCollection getMakeCollection() {
        return makeCollection;
    }
    public void setMakeCollection(MakeCollection makeCollection) {
        this.makeCollection = makeCollection;
    }
 

 

//打折策略接口
public interface MakeCollection {
    //根据打折类型收款
    double makecollection(Commodity commodity);
}
 

 

//默认不打折
public class Default implements MakeCollection {
    public double makecollection(Commodity commodity) {
        return commodity.total();
    }
}
 

 

//八折策略
public class Discount8 implements MakeCollection {
    public double makecollection(Commodity commodity) {
        return commodity.total() * 0.8;
    }
}
 

 

 

//打五折策略
public class Half implements MakeCollection {
    //打五折
    public double makecollection(Commodity commodity) {
        return commodity.total() * 0.5;
    }
}

 //满500减200策略

public class Full500by200 implements MakeCollection {
    public double makecollection(Commodity commodity) {
        int i = (int)commodity.total() / 500;
        return (commodity.total() - (200 * i));
    }
}
 

 

 

//商品类
public class Commodity {
    //价格
    private double price;
    //数量
    private double quantity;
    //总价
    public double total(){
        return this.price * this.quantity;
    }
    /**
     * 构造方法
     * @param price    价格
     * @param quantity 数量
     */
    public Commodity(double price, double quantity) {
        this.price = price;
        this.quantity = quantity;
    }

    //getter & setter
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public double getQuantity() {
        return quantity;
    }
    public void setQuantity(double quantity) {
        this.quantity = quantity;
    }
}

 //收款测试类

public class CheckOutTest {
    public static void main(String[] args) {
//        商品类
        Commodity c = new Commodity(500,3);
//      选择默认策略
        CheckOut checkOut = new CheckOut(new Default(),c);
        System.out.println("默认时,您需要付:"+ checkOut.makeCollection());
//      选择满500减200策略
        checkOut.setMakeCollection(new Full500by200());
        System.out.println("满500减200时,您需要付:"+ checkOut.makeCollection());
        //选择打八折策略
        checkOut.setMakeCollection(new Discount8());
        System.out.println("打八折时,您需要付:"+ checkOut.makeCollection());
//      选择打对折策略
        checkOut.setMakeCollection(new Half());
        System.out.println("打对折时,您需要付:"+ checkOut.makeCollection());
    }
}

 //运行结果

默认时,您需要付:1500.0
满500减200时,您需要付:900.0
打八折时,您需要付:1200.0
打对折时,您需要付:750.0
 

 

     策略模式将变化的方法(算法)通过一个接口进行抽象,然后在使用者中定义了这个接口,并在某个方法(算法)中调用了这个接口的方法(算法),处理或者返回结果。完成了算法在使用者内部解耦的作用。而使用者要更换方法(算法)的时候,可以通过setter方法进行灵活的更换。

策略模式就像我们游戏中的技能,就拿Dota来说,一个角色一般拥有四个技能,当我们技能能够使用的时候(级别满了,当然,CD时间也要有),我们可以灵活的使用技能,技能之间能互换,只是你在按某个技能键的时候,系统自动帮你调用了对应的招式而已。如果你是矮人狙击手,那么,当你发送散弹的时候,就是在调用你具体的技能在地图的某个区域对附近的人进行减血。技能的使用就类似角色使用策略模式来完成操作的。

 

以上是我个人对策略模式的理解以及总结,拿出来只是为了共同勉励。如果有错误的地方欢迎指正。

 

参考资料:

Head first 设计模式 (美)弗里曼(Freeman,E.)

大话设计模式  程杰

 

 

 

 

 

  • 大小: 27 KB
  • 大小: 5.1 KB
  • 大小: 26.9 KB
  • 大小: 26.9 KB
  • 大小: 23.2 KB
  • 大小: 11.8 KB
  • 大小: 38.9 KB
分享到:
评论

相关推荐

    设计模式--策略模式java例子

    策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在Java中,策略模式通常用于替换硬编码的条件语句,使代码更加灵活、可扩展和易于维护。下面我们将详细探讨策略模式的核心概念、实现方式以及在实际...

    java设计模式--策略模式

    策略模式是Java设计模式中的一种行为模式,它允许在运行时选择算法或策略,从而提供了更大的灵活性。在HeadFirst的《设计模式》一书中,第一章深入浅出地讲解了这一模式,通过实例帮助读者理解其核心概念和应用场景...

    北大青鸟设计模式--策略模式

    北大青鸟关于设计模式的PPT,讲述的非常清晰,对于初学设计模式的人来说,非常有用。本篇是关于策略模式的PPT

    设计模式--策略模式StrategyPattern

    策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在软件开发中,我们经常遇到需要根据不同的条件或场景来执行不同算法的情况。策略模式提供了一种将算法族封装到各自独立的类中,并在运行时选择具体...

    c++设计模式-行为型模式-策略模式

    c++设计模式-行为型模式-策略模式;qt工程;c++简单源码; 策略(Strategy)模式的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于...

    JAVA-设计模式-行为型模式-策略模式

    JAVA-设计模式-行为型模式-策略模式

    C++设计模式--基于Qt4开源跨平台开发框架

    《C++设计模式--基于Qt4开源跨平台开发框架》一书主要探讨了如何在C++编程中利用设计模式,并结合Qt4框架进行高效的跨平台应用开发。设计模式是软件工程中的重要概念,它们是经过时间和实践验证的解决特定问题的模板...

    php设计模式-策略模式-例题学习

    在这个"php设计模式-策略模式-例题学习"的例子中,我们将深入理解策略模式的运用及其在PHP中的实现。 首先,让我们来看看核心的类和接口: 1. `HandStrategyInterface.php`: 这个文件定义了一个接口`...

    设计模式-策略者

    在《设计模式-策略者》这篇文章中,作者深入浅出地介绍了策略模式的基本概念、结构和实现方式。文章可能涵盖了以下几个关键知识点: 1. **模式定义**:策略模式允许在运行时选择不同的算法或策略,提供了一种用面向...

    设计模式-策略模式-c++版

    策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在C++中,策略模式主要用于封装一系列算法,并让它们之间可以互相替换,使得算法的变化独立于使用算法的客户。这种模式通常涉及三个主要角色:策略...

    设计模式-Java语言中的应用

    通过阅读《设计模式-Java语言中的应用》,读者不仅可以掌握设计模式的基本概念和原理,还能学习到如何在实际项目中选择合适的设计模式,以及如何优雅地在Java代码中实现这些模式。这将有助于提升开发者的编程技巧,...

    java设计模式---诙谐易懂版

    1. 策略模式(Strategy Pattern)是一种行为设计模式,允许在运行时选择算法的行为。策略模式的意图是定义一系列算法,将每个算法封装起来,并使它们可以互换。策略模式让算法的变化独立于使用算法的客户端。在提供...

    设计模式---策略者模式

    策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在软件开发中,我们经常遇到需要在不同时间或根据不同条件执行不同算法的情况。策略模式允许我们将算法封装到独立的可互换的策略类中,使得算法的变化...

    C++设计模式-基于QT4开源跨平台开发框架 源码

    5. **策略模式** - QT4的信号和槽可以视为一种策略,开发者可以根据需要连接不同的槽函数来改变对象的行为。 6. **命令模式** - 可以利用QT4的QMetaObject系统和QSignalMapper来实现命令模式,通过信号触发不同的...

    java设计模式-策略模式

    在这个“java设计模式-策略模式”的示例中,我们将深入探讨如何使用策略模式来实现一个简单的超市促销系统。 策略模式的核心思想是定义一系列的算法,并将每一个算法封装起来,使它们可以互相替换。这使得算法的...

    设计模式-策略模式

    策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在iOS开发中,策略模式经常被用来处理算法的可变性和封装多种行为。通过使用策略模式,开发者可以将算法封装在独立的策略类中,使得算法可以独立于...

    设计模式-策略模式源代码

    策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在.NET开发中,策略模式经常被用来处理算法的可变性和封装多种算法于一个系统的情况。此压缩包文件包含的是关于策略模式的源代码示例,以及可能的一个...

    设计模式-画笔程序

    描述中的"利用设计模式思想扩展的画皮程序"暗示了可能使用了"策略模式"。在画笔程序中,不同的绘画工具(如铅笔、刷子、橡皮擦等)可以看作是策略,每种工具都有其特定的绘制策略。用户选择不同的工具时,实际上是在...

    设计模式精解-GoF-23种设计模式解析--附C++源代码

    - 策略模式(Strategy):定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。 - 模板方法模式(Template Method):定义一个操作中的算法骨架,而将一些步骤延迟到子类中。 - 访问者模式...

Global site tag (gtag.js) - Google Analytics