设计模式系列之六:策略模式

简介:

前言

策略模式是设计模式中的行为型模式,所谓行为型就是其主要使用在方法有很大灵活性的情况。而之前的工厂模式主要是对创建对象的优化,减少程序中使用new对象的次数。策略模式在Java源码中也是很常见的,比如我们要比较两个对象的大小,既可以使用默认的Comparable接口,也可以实现自定义的比较规则,即实现Comparator接口。这两种比较比较方法都是不同比较规则的体现,属于不同的策略。策略模式从定义上是这么说的:定义了算法家族,把这些不同的算法封装起来,让他们之间可以相互替换。从而使得算法的替换不会影响调用者的变化。光从字面上感觉还不是特别清晰,简单来说就是要办成一件事可以有不同的方法,这些方法都是属于一个家族的,所以从本质上来讲,这些方法是没有区别的。因为外界调用的时候只需要知道这个家族的代表是谁就可以了,其他的调用者并不需要关心。

问题背景

实现一个收银软件,输入单价与数量计算总价格。商场的收费方式可能有多种而且还会随时改变。

编码实践一,使用简单工厂模式实现

//SimpleFactory Mode
public abstract class Cash{
    public abstract double calculateRealCash(double money);
}

public class NormalCash extends Cash{
    public double calculateRealCash(double money){
        return money;
    }
}

public class DiscountCash extends Cash{
    //打折点
    private double discountPoint;

    public DiscountCash(double discountPoint){
        this.discountPoint = discountPoint;
    }

    public double getDiscountPoint(){
        return discountPoint;
    }

    public void setDiscountPoint(double discountPoint){
        this.discountPoint = discountPoint;
    }

    public double calculateRealCash(double money){
        return Math.floor(money * discountPoint);
    }
}

public class RebateCash extends Cash{

    private String rebateCondition;
    private String moneyOfRebate;

    public RebateCash(String rebateCondition,String moneyOfRebate){
        this.rebateCondition = rebateCondition;
        this.moneyOfRebate = moneyOfRebate;
    }

    public String getRebateCOndition(){return rebateCondition;}
    public void setRebateCondition(String rebateCondition){this.rebateCondition = rebateCondition;}
    public String getMoneyOfReabte(){return moneyOfRebate;}
    public void setMoneyOfReabte(String moneyOfRebate){this.moneyOfRebate = moneyOfRebate;} 

    public double calculateRealCash(double money){
        return money > Double.valueOf(rebateCondition) ? money - Math.floor(money * Double.valueOf(moneyOfRebate) / Double.valueOf(rebateCondition)) : money;
    }
}

public class CashFactory{

    public static Cash createCashObject(int type){
        Cash cash = null;;
        switch(type){
            case 1:
                cash = new NormalCash();
                break;
            case 2:
                cash = new DiscountCash(0.85);
                break;
            case 3:
                cash = new RebateCash("300","100");
                break;
            default:
                cash = new NormalCash();
                break;
        }
        return cash;
    }
}

public class Test{
    public static void main(String[] args){
    Scanner in = new Scanner(System.in);

    System.out.println("price:");
    double price = in.nextDouble();
    System.out.println("num:");
    int num = in.nextInt();
    double price2 = num * price;

    System.out.println("Choose type to calculate the total price:\n" 
        + " 1 is normal cash\n 2 is 80% discount cash\n 3 is full 300 return 100");

    int type = in.nextInt();

    Cash cash = CashFactory.createCashObject(type);
    System.out.println("Total price is " + totalPrice);
    }
}

测试结果:

测试结果

编码实践二,使用策略模式实现

public class CashContext{
    private Cash cash;

    public CashContext(int type){
        switch(type){
            case 1:
                cash = sm.new NormalCash();
                break;
            case 2:
                cash = sm.new DiscountCash(0.85);
                break;
            case 3:
                cash = sm.new RebateCash("300","100");
                break;
        }
    }

    public double getRealMoney(double money){
        return cash.calculateRealCash(money);
    }
}

//测试
public class Test{
    public static void main(String[] args){
    Scanner in = new Scanner(System.in);

    System.out.println("price:");
    double price = in.nextDouble();
    System.out.println("num:");
    int num = in.nextInt();
    double price2 = num * price;

    System.out.println("Choose type to calculate the total price:\n" 
        + " 1 is normal cash\n 2 is 80% discount cash\n 3 is full 300 return 100");

    int type = in.nextInt();

    CashContext cashContext = new CashContext(type);
    double totalPrice = cashContext.getRealMoney(price2);
    System.out.println("Total price is " + totalPrice);
    }
}

测试结果2:

测试结果2

OK,现在使用两种方法的测试结果是一致的,那么来看看两种设计模式的区别。对比类CashContextCashFactory我们可以发现,策略模式封装了一个Cash对象,而这个对象是所有收费方法类的超类,那么在计算最后的钱数的时候,CashContext只是创建了一个实例,使用了一个CashContext类,而使用简单工厂模式在计算的时候,使用了CashFactory和Cash两个类,那么使用类的个数的多少又有什么关系呢?在Java中提倡依赖倒转原则,意思就是要要面向抽象编程而不是面向细节编程。延伸来讲就是,对外暴露的细节越少越好,因为对外暴露的细节越少,因需求变更而修改的代码越少,同时这也是开放-封闭原则的体现,所以从这点讲简单工厂模式对外暴露的字节大于策略模式,所以在面向抽象编程上更胜一筹。当然策略模式也有其不足,比如在构造函数中添加了逻辑判断语句,,与使用构造函数的初衷不是很符合,所以创建一个单独的方法或者类来单独完成类实例化的工作会更好一些。注意到,前面的CashFactory类的createCashObject()方法正是用来创建Cash对象的,所以可以把CashContext构造函数创建Cash对象的方法直接改为createCashObject()方法。这样每一个类的调用关系又进一步解耦了。

最后,对策略模式做一个简单的总结:

  1. 每个算法类封装了不同的实现,但完成的是相同的工作。这样就把算法实现类与使用算法类的类解耦
  2. 简化了单元测试
  3. 对外部暴露了更少的实现细节,符合开放-封闭原则
  4. 当算法实现类不断增加的时候,在Context类中增加的switch分支会越来越多
目录
相关文章
|
2月前
|
设计模式 算法 测试技术
PHP中的设计模式:策略模式的应用与实践
在软件开发的浩瀚海洋中,设计模式如同灯塔,指引着开发者们避开重复造轮子的暗礁,驶向高效、可维护的代码彼岸。今天,我们将聚焦于PHP领域中的一种重要设计模式——策略模式,探讨其原理、应用及最佳实践,揭示如何通过策略模式赋予PHP应用灵活多变的业务逻辑处理能力,让代码之美在策略的变换中熠熠生辉。
|
1天前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
9 2
|
16天前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
42 2
|
1月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
本教程详细讲解Kotlin语法,适合深入学习。快速入门可参考“简洁”系列教程。本文通过游泳运动员的案例,介绍策略模式及其在Kotlin中的改良应用,利用高阶函数简化代码结构,提高灵活性。
31 3
|
1月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
本教程详细讲解Kotlin语法,适合深入学习。快速入门可参考“简洁”系列教程。本文介绍策略模式在Kotlin中的应用,通过游泳运动员的例子,展示如何使用接口和高阶函数实现策略模式,使代码更简洁、灵活。
28 2
|
1月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
62 3
|
1月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
27 3
|
1月前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入解析与实践
【10月更文挑战第9天】 策略模式是一种行为设计模式,它允许在运行时选择算法的行为。在PHP开发中,通过使用策略模式,我们可以轻松切换算法或逻辑处理方式而无需修改现有代码结构。本文将深入探讨策略模式的定义、结构以及如何在PHP中实现该模式,并通过实际案例展示其应用价值和优势。
30 1
|
1月前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入解析与应用
【10月更文挑战第8天】 在软件开发的浩瀚宇宙中,设计模式如同星辰指引,照亮了代码设计与架构的航道。本文旨在深入探索PHP语境下策略模式(Strategy Pattern)的精髓,不仅剖析其内核原理,还将其融入实战演练,让理论在实践中生根发芽。策略模式,作为解决“如何优雅地封装算法族”的答案,以其独特的灵活性与扩展性,赋予PHP应用以动态变换行为的能力,而无需牵动既有的类结构。
28 2
|
1月前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入解析与实践
在PHP开发中,设计模式是提高代码可读性、可维护性和扩展性的重要工具。本文将深入探讨策略模式这一行为型设计模式,通过分析其定义、结构、使用场景以及在PHP中的实际应用,帮助开发者更好地理解和运用策略模式来优化自己的项目。不同于传统摘要的简洁概述,本文摘要部分将详细阐述策略模式的核心理念和在PHP中的实现方法,为读者提供清晰的指引。

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    43
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    50
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    58
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    63
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    58
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    42
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    110
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78