`
songry
  • 浏览: 84383 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Clojure与java设计模式(3) 策略模式

阅读更多

 

注:本文基于jdk1.6和Clojure1.2

策略模式

    策略模式是指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,

但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。(维基百科)

 

    在面向对象语言中,这可能是最常见的模式,可能很多人在听说过这个算法之前就已经使用过它了。

 

    首先,我们定义一个策略接口:

/**
 * 缴税策略接口
 * @author RoySong
 */
public interface IPayTaxStrategy {

	/**
	 * 根据收入计算需要交纳的个人所得税
	 * @param salary
	 * @return
	 */
	public Double payTax(Double salary);
}
 

    然后,我们实现天朝个税和美帝个税的实现策略:

/**
 * 天朝个税策略
 *@author RoySong
 */
public class ChinaPayTaxStrategy implements IPayTaxStrategy {

	/* 应纳个人所得税税额= 应纳税所得额× 适用税率- 速算扣除数,针对月薪
	 * 应纳税所得额=扣除三险一金后月收入 -扣除标准 
	 * 在这儿,我们假定三险一金为150,扣除标准为3500
	 * @see strategy.IPayTaxStrategy#payTax(java.lang.Float)
	 */
	@Override
	public Double payTax(Double salary) {
		Double oughtPay = salary - 150 - 3500;//应纳税所得额
		if(oughtPay <= 0)
			return 0.0;
		if(oughtPay <= 1500)
			return oughtPay * 0.03;
		if(oughtPay > 1500 && oughtPay <= 4500)
			return oughtPay * 0.1 - 105;
		if(oughtPay > 4500 && oughtPay <= 9000)
			return oughtPay * 0.2 - 555;
		if(oughtPay > 9000 && oughtPay <= 35000)
			return oughtPay * 0.25 - 1005;
		if(oughtPay > 35000 && oughtPay <= 55000)
			return oughtPay * 0.3 - 2755;
		if(oughtPay > 55000 && oughtPay <= 80000)
			return oughtPay * 0.35 - 5505;
		if(oughtPay > 80000)
			return oughtPay * 0.45 - 13505;
		return null;
	}

}

/**
 * 美帝个税策略
 *@author RoySong
 */
public class USAPayTaxStrategy implements IPayTaxStrategy {

	/* 取的是已婚人士的个税策略,针对年薪
	 * @see strategy.IPayTaxStrategy#payTax(java.lang.Double)
	 */
	@Override
	public Double payTax(Double salary) {
                if(salary <= 0)
			return 0.0; 
                if(salary <= 16750)
			return salary * 0.1;
		if(salary > 16750 && salary <= 68000)
			return 1675 + (salary - 16750) * 0.15;
		if(salary > 68000 && salary <= 137300)
			return 9362.5 + (salary - 68000) * 0.25;
		if(salary >= 137300 && salary <= 209250)
			return 26687.5 + (salary - 137300) * 0.28;
		if(salary >= 209250 && salary <= 373650)
			return 46833.5 + (salary - 209250) * 0.33;
		if(salary > 373650)
			return 101085.5 + (salary - 373650) * 0.35;
		return null;
	}

}

 

    然后我们开始定义计算实际收入的类:

/**
 * 薪水计算类
 *@author RoySong
 */
public class PayMent {

	private IPayTaxStrategy payTaxStrategy;
	
	/**
	 * 计算实际收入
	 * @param incoming
	 * @return
	 */
	public Double getRealSalary(Double incoming){
		return incoming - payTaxStrategy.payTax(incoming);
	}

	public void setPayTaxStrategy(IPayTaxStrategy payTaxStrategy) {
		this.payTaxStrategy = payTaxStrategy;
	}
}
 

    然后我们调用一下看看:

public class StrategyTest {

	public static void main(String[] args){
		PayMent payMent = new PayMent();
		//月收入5000元的国人能够拿到手的钱
		payMent.setPayTaxStrategy(new ChinaPayTaxStrategy());
		System.out.println("天朝月入5000到手:"+payMent.getRealSalary(5000.0));
		//年入50000刀的美帝能够拿到手的钱
		payMent.setPayTaxStrategy(new USAPayTaxStrategy());
		System.out.println("美帝年入50000到手:"+payMent.getRealSalary(50000.0));
	}
}
 

    运行结果是:

天朝月入5000到手:4959.5
美帝年入50000到手:43337.5
 

     嗯,天朝老百姓果然要比美帝轻松很多。这是开玩笑的。从这个例子中,我们可以看到,不变的部分是实际收入=

总收入- 个税。而变化的部分则是个税的计算手段。策略模式就是将变化的部分提取出来,以多态的方式进行封装。如果

需要添加新的个税计算方式,比如说阿三的个税策略,那么我们只需要新添加IPayTaxStrategy接口的一个实现类即可,

而不用去修改原来的个税计算策略;如果天朝的个税计算策略有变动,我们也只需改动或者重写ChinaPayTaxStrategy

类即可,也不会影响到其他的个税计算策略。

 

    在上篇文章 中,我们已经提过Clojure中的函数可以作为参数和返回类型,那么策略模式对于Clojure来说,根本就不是

模式而是常态了。

 

    首先我们先定义一个工具函数,用于判断某个数字的区间范围:

(defn between [source start end]
	    (if (>= source start)
		(if (< source end)
		    true
		    nil)
		nil))
 

    然后,定义天朝和美帝的个税策略:

(defn china-tax [salary]
  (let [ought-pay (- salary 150 3500)]
    (cond
      (<= ought-pay 0) 0
      (between ought-pay 0 1500) (* ought-pay 0.03)
      (between ought-pay 1500 4500) (- (* ought-pay 0.1) 105)
      (between ought-pay 4500 9000) (- (* ought-pay 0.2) 555)
      (between ought-pay 9000 35000) (- (* ought-pay 0.25) 1005)
      (between ought-pay 35000 55000) (- (* ought-pay 0.3) 2755)
      (between ought-pay 55000 80000) (- (* ought-pay 0.35) 5505)
      (> ought-pay 80000) (- (* ought-pay 0.45) 13505))))

(defn usa-tax [salary]
  (cond
    (<= salary 0) 0
    (between salary 0 16750) (* salary 0.1)
    (between salary 16750 68000) (+ (* (- salary 16750) 0.15) 1675)
    (between salary 68000 137300) (+ (* (- salary 68000) 0.25) 9362.5)
    (between salary 137300 209250) (+ (* (- salary 137300) 0.28) 26687.5)
    (between salary 209250 373650) (+ (* (- salary 209250) 0.33) 46833.5)
    (> salary 373650) (+ (* (- salary 373650) 0.35) 101085.5)))
 

    最后,我们定义计算实际收入的函数:

(defn payment [fn incoming]
  (- incoming (fn incoming)))
 

    然后用同样的条件来调用看看:

=> (println "天朝月入5000到手:" (payment #'china-tax 5000))
天朝月入5000到手: 4959.5
nil
=> (println "美帝年入50000到手:" (payment #'usa-tax 50000))
美帝年入50000到手: 43337.5
nil
 

    得到了同样的结果,不是吗?策略模式的精髓在于通过在运行中注入不同的对象来采取不同的策略,在java中要达到

这个目的,我们需要抽象出策略接口,添加策略实现类,然后在上下文中设置注入点;而在Clojure中,只需要在调用

策略时将对应的策略函数作为参数传入即可。

 

分享到:
评论

相关推荐

    HTTPKit-Clojure的高性能事件驱动HTTP客户端服务器

    HTTPKit是专门为Clojure设计的一款高性能、事件驱动的HTTP客户端和...其高效、简洁的设计理念使得它成为Clojure网络编程的首选库之一。通过深入理解和使用HTTP Kit,开发者可以构建出响应迅速、可扩展性强的Web服务。

    java每月新闻杂志9

    6. **最佳实践**:针对Java编程的编码规范、设计模式、测试策略和持续集成等内容,杂志会分享专家的观点和经验,帮助开发者提高代码质量和可维护性。 7. **社区活动**:JavaOne、Devoxx等大型技术会议的亮点和重要...

    clj-http-hystrix:Clojure库,将clj-http请求包装为hystrix命令

    5. **circuit-breaker** - 断路器模式,一种设计模式,允许系统在故障发生时快速失败,而不是尝试处理越来越多的错误请求。 6. **clj-http** - 是一个Clojure的HTTP客户端库,提供了丰富的HTTP请求功能,可以用来与...

    lfecljapp:使用OTP和监督树的示例LFEClojure多节点系统

    - "otp":Open Telecom Platform,Erlang的核心特性之一,提供了构建容错系统和分布式服务的工具和设计模式。 - "howto":可能表示这个项目是一个教程或指南,指导用户如何在LFEClojure中实现OTP和监督树。 - ...

    clj:普通Lisp的基本Clojure功能

    4. **并行与并发**:Clojure在设计时特别考虑了现代多核硬件的并行处理,其核心数据结构如原子(atoms)、引用(refs)和代理(agents)提供了安全的并发更新机制。 5. **JVM集成**:Clojure是运行在JVM上的,可以...

    puertorico:Clojure中的波多黎各棋盘游戏

    通过这个项目,开发者不仅可以学习到波多黎各棋盘游戏的策略,还可以深入理解Clojure和Clojurescript的高级特性,包括它们如何与JavaScript生态系统协同工作,以及如何利用函数式编程思想来设计复杂系统。...

    app-from-scratch:有关清洁架构和Clojure的书

    它支持复杂查询、事务处理和多种数据类型,与Clojure的Java互操作性良好,可以方便地集成到Clojure应用中。 5. **项目结构**:`app-from-scratch-master`目录可能包含了Clojure项目的典型结构,如源代码文件夹、...

    clojure-conj-2014-paradigms-of-core-async:Clojure Conj 2014 演讲 - 核心异步范式

    7. **与其他技术的集成**:由于Clojure可以与Java和其他JVM语言互操作,`core.async`也可以很好地融入到已有的异步基础设施中,如与Java的Future、CompletableFuture或Netty等进行结合。 8. **最佳实践**:演讲者...

    babel:一个有组织的文化Clojure项目的Leiningen项目模板

    "Babel:一个有组织的文化Clojure项目的Leiningen项目模板" 指的是Babel,它是一个专为Clojure项目设计的Leiningen模板。Leiningen是Clojure社区广泛使用的构建自动化工具,它使得创建、构建和管理Clojure项目变得...

    nomnom.bunnicula:用于构建RabbitMQ消费者和发布者的Clojure框架

    `nomnom.bunnicula` 是一个专为Clojure开发者设计的框架,旨在简化与RabbitMQ的交互,帮助构建高效、可靠的RabbitMQ消费者和发布者。RabbitMQ是一种流行的消息队列系统,基于AMQP(Advanced Message Queuing ...

    DSLs_in_Action.pdf

    这部分是整个书的精华所在,它不仅介绍了内部DSL(也称为嵌入式DSL)和外部DSL的设计模式和实现方法,而且还提供了一些主流编程语言(如Ruby、Groovy、Clojure和Scala)的内部DSL设计实例。内部DSL是嵌入到宿主语言...

    光子:光子是具有冷热事件流的事件存储

    在本文中,我们将深入探讨光子的核心特性、工作原理以及如何与Java、Clojure等编程语言集成。 1. **事件存储**: 光子作为事件存储,负责记录系统的不可变历史。事件是系统状态变化的记录,它们以时间顺序排列,...

    Seven.Languages.in.Seven.Weeks_7天7语言_

    Scala与Java互操作性强,是大数据处理框架Spark的主要编程语言。 7. **F#**:F#是.NET框架下的函数式编程语言,它融合了面向对象和函数式编程的特点。F#的类型推断和运算符重载简化了代码编写,而它的异步工作流则...

    从零开始学Storm+第2版(2016).pdf

    学习 Storm,你需要理解分布式计算的基本原理,熟悉 Java 或者 Clojure 开发,因为 Storm 的 API 主要是基于这两种语言。此外,了解消息队列如 Kafka 或者 MQTT,以及基本的数据存储系统,将有助于你更好地设计和...

    Storm企业级应用实战、运维和调优

    3. **开发实时应用**:通过实例,读者将学习如何使用Java或Clojure等编程语言编写Spout和Bolt,构建自己的实时处理拓扑。书中可能还涵盖了如何使用 Trident API 来实现状态管理和复杂的窗口操作。 4. **监控与故障...

    sytac-core-async:在Sytac Devjam上演示的幻灯片和代码

    通过分析这个仓库,我们可以深入理解如何在Clojure中实现异步操作,包括但不限于使用`future`, `go`块,核心异步库(如`clojure.core.async`)以及其他相关工具和设计模式。 **知识点详述:** 1. **Clojure函数式...

    2012年SOA最佳技巧集 TOP 10.pdf

    在2012年,有许多新的Java Web应用工具被引入,如Spring MVC、Struts 2等,这些工具与传统的Java Web开发工具相比,提供了更多的功能性和灵活性。通过对这些新旧工具进行比较,开发者可以更好地理解它们各自的优点和...

    buddy-auth:用于基于环和环的Web应用程序的身份验证和授权功能

    5. **Clojure语言**:Clojure是一种基于Lisp的函数式编程语言,运行在Java虚拟机上。它以其并发处理能力、简洁语法和强大的元编程特性而闻名,常用于构建Web应用和服务。 6. **库的使用与集成**:在Clojure应用中,...

    JVM dynamic languages MetaobjectProtocol-开源

    元对象协议(MOP)是一种设计模式,它允许程序在运行时检查和修改自身的结构和行为。在动态语言中,MOP使得类、方法、属性等可以被视为对象,进而支持诸如反射、元编程、动态类型调整等高级特性。MOP的核心思想是...

Global site tag (gtag.js) - Google Analytics