专栏首页Java全栈java设计模式之策略模式及项目中的应用

java设计模式之策略模式及项目中的应用

转载请注意出处:http://blog.csdn.net/zcm101

设计模拟人生游戏

今天开始,我们LazyCoder准备着手开发一款模拟人生游戏,首先从设计人物开始,我们设想我们设计的人物可以讲话,吃东西,睡觉,他们的样子也都不一样。我们想到了继承,于是有了第一个类Person,之后我们再设计各种各样的人,家族里有很多人,有Father,Mother,Brother……他们的样子长得不一样,于是我们为每个人物设计一个类,他们都继承Person,并实现各自的display方法,display就交给美工们来做吧

。不会美工的童鞋举手,我第一个举手。

下面是我们第一个版本的代码:

package com.lazycode.v1;

public abstract class Person {

	public void sleep(){
		System.out.println("Person sleep");
	}
	
	public void eat(){
		System.out.println("Person eat");
	}
	
	public void speak(){
		System.out.println("Person speak");
	}
	
	public abstract void display();
}
package com.lazycode.v1;

public class Father extends Person {

	@Override
	public void display() {
		System.out.println("Father display");
	}

}
package com.lazycode.v1;

public class Mother extends Person {

	@Override
	public void display() {
		System.out.println("Mother display");
	}

}
package com.lazycode.v1;

public class Brother extends Person {

	@Override
	public void display() {
		System.out.println("Brother display");
	}

}

大家每天吃饱了睡,睡醒了吃,聊聊天,愉快的一天就过去了……

问题来了

随着模拟人生业务的发展,我们开始进军海外,于是,设计了个远房亲戚,来自美国的Sister,而我们现有的Person类,只支持讲中文。额—— 在Sister里覆盖下speak方法吧,让她讲英语。从此我们将暗无天日!随着人物的增多,我们每天都重复着为每个人加入讲英语的方法,而且是同一段代码,我要疯了,这可不是懒程序员的风格!而且每新建个人物时,我都得想一下,他应该讲中文还是讲英文呢,这我真的要疯了!!看来得改进我们的Person类了。

怎么办怎么办……

Person里加个国籍,在speak方法里加判断,根据国据,判断讲的语言? 疯了吧你!万一出现一个牛人,会八种语言怎么办?全世界上千种语言,你打算每加入一种新的语言就改下Person类吗,每改动一次Person类,对原有的代码就增加出风险的机率。再想想~~~

春天来了

我们发现所有中国人都讲汉语,所有美国人都讲英语,之后还会出现讲法语、德语的,我们可以每种语言都提炼成一个类,将speak提出成接口LanSpeak。一组语言类就这么出来了。

package com.lazycode.v2;

public interface LanSpeak {

	public void speak();
}
package com.lazycode.v2;

public class ChiSpeak implements LanSpeak {

	@Override
	public void speak() {
		System.out.println("Speak Chinese");
	}

}
package com.lazycode.v2;

public class EngSpeak implements LanSpeak {

	@Override
	public void speak() {
		System.out.println("Speak English");
	}

}

那么如何将Person类和LanSpeak接口联系起来呢?

我们再思考,Father见到Sister后,Sister不会讲中文,我们得让Father讲英文,也就是说Father在不同的场景中,能够中英文切换,试着将LanSpeak变成Person类里的一个属性(你一定听过面向接口编程,对的,我们在Person类里用到的时LanSpeak接口,而不是具体的ChiSpeak,EngSpeak。),在运行过程中,设置LanSpeak为不同的LanSpeak实现类,不就可以讲不同的语言吗。看下我们重新设计出来的Person类:

package com.lazycode.v2;

public abstract class Person {
	
	public LanSpeak lanSpeak;

	public void sleep(){
		System.out.println("Person sleep");
	}
	
	public void eat(){
		System.out.println("Person eat");
	}
	
	public void speak(){
		//输出具体讲话的人
		System.out.println(this.getClass().getName() + ":");
		lanSpeak.speak();
	}
	
	public abstract void display();

	public LanSpeak getLanSpeak() {
		return lanSpeak;
	}

	public void setLanSpeak(LanSpeak lanSpeak) {
		this.lanSpeak = lanSpeak;
	}
}

我们加入了个lanSpeak属性,set,get,在speak中, 不在是直接输出讲话信息了,而是 委托给了lanSpeak,要讲什么语言由他来决定。

再来看具体的人物,他们在被创建的时候,我们就默认给他设置一种语言,Father讲中文,USASister讲英文,所以在构造方法里需传入LanSpeak实现类。

package com.lazycode.v2;

public class Father extends Person {

	public Father(LanSpeak lanSpeak){
		this.lanSpeak = lanSpeak;
	}
	
	@Override
	public void display() {
		System.out.println("Father display");
	}

}
package com.lazycode.v2;

public class USASister extends Person {

	public USASister(LanSpeak lanSpeak) {
		this.lanSpeak = lanSpeak;
	}

	@Override
	public void display() {
		System.out.println("USASister display");
	}

}

好了,代码改造得差不多了,来看看怎么让Father和Mother讲中文,然后和USASister讲英文

package com.lazycode.v2;

public class Main {

	public static void main(String[] args) {
		//初始化语言
		ChiSpeak chiSpeak = new ChiSpeak();
		EngSpeak engSpeak = new EngSpeak();
		//初始化人物
		Father father = new Father(chiSpeak);
		Mother mother = new Mother(chiSpeak);
		USASister usaSister = new USASister(engSpeak);
		//father和mother交谈
		father.speak();
		mother.speak();
		//来自美国的妹妹插话了
		usaSister.speak();
		//让father讲英文
		father.setLanSpeak(engSpeak);
		father.speak();
	}

}

输出:

com.lazycode.v2.Father: Speak Chinese com.lazycode.v2.Mother: Speak Chinese com.lazycode.v2.USASister: Speak English com.lazycode.v2.Father: Speak English

策略模式就这么出来了,下面来看些理论上的东西吧。

概念

策略模式(Strategy):它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。(原文:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.)

LanSpeak就是我们抽象出来的一组算法的接口,这组算法(ChiSpeak, EngSpeak)在程序运行的时候可以互相替换。

优点:很明显,扩展性很好;还有另一个隐性优点,这组语言类,脱离了Person,可以在其它地方用,比如广播。

缺点:很明显,扩展多了类就要爆棚了,而且客户端需要知道所有的算法,需要知道目前共实现了几种语言类。不过想比扩展性优点来说,这些还是可以容忍的。

策略模式一般会有三个角色:抽象策略角色(LanSpeak),具体策略角色(ChiSpeak),上下文(Person)

补充

回头再看看我们的代码,其实我们的Father类可以用v1包里的代码,不用做修改,因为我们的Person类里已经提供了SetLanSpeak方法了,每个人物都可以动态设置语言,而不用初始化就设置语言。我个人还是觉得这种写法会好点,我们现在只遇到了speak一组算法,以后可能会遇到move族算法,人物可以移动,但是每个人移动的方法不一样,有的是跑的,有的是走的,有的坐轮椅,有的骑自行车……还会有各种各样的算法族,难道每加一种算法族,所有的类的构造函数都改一遍?你这是要疯吧!!

项目实践

策略模式可以说是在项目中应用最多的模式之一,举一个最常见的例子,现在随便找个java项目,看看分层结构,是不是都会有一层service,一层dao,service里调用dao从而访问数据库。想一下,是不是有策略模式的影子了。

假设我们的项目有一个dao接口,叫CommonDao,有最基本的增删改查方法。我们再实现两个dao,分别是HibernateDaoImpl,JdbcDaoImpl,从名字就知道有什么区别吧。假如我们有一个PersonService,里面有个commonDao接口,我们通过Spring将HibernateDaoImpl注入到PersonService中。注意这个注入的过程,其实就是策略模式的体现,我们使用hibernateDaoImpl注入到PersonService,其实就是告诉service,我要使用hibernate来访问数据库这种策略。我们可以通过Spring的注入配置,来实现不同的策略。

假设哪天出现了个新的持久化框架,比如叫Lazycoder,那我们就可以实现LazycoderDaoImpl,然后将它通过Spring配置注入到PersonService中。

就做了两件事,增加一个策略,将这个策略代替旧的策略。So easy, 妈妈再也不用担心我的学习了。

思考

1. 随着业务需要,我们加入了德语,如何扩展?

2. 在补充里提到了给Person加入move动作,怎么重新设计Person类?

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • java设计模式之策略模式

    纪莫
  • Java设计模式之策略模式

    刘备要到江东娶老婆了,走之前诸葛亮给赵云(伴郎)三个锦囊妙计,说是按天机拆开解决棘手问题,嘿,还别说,真是解决了大问题,搞到最后是周瑜陪了夫人又折兵呀,那咱们先...

    CoderJed
  • java设计模式之策略模式

    策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类...

    小小鱼儿小小林
  • 设计模式 | 策略模式及典型应用

    在软件开发中,我们也常常会遇到类似的情况,实现某一个功能有多条途径,每一条途径对应一种算法,此时我们可以使用一种设计模式来实现灵活地选择解决途径,也能够方便地增...

    小旋锋
  • 图解Java设计模式之策略模式

    1)有各种鸭子(比如 野鸭、北京鸭、水鸭等)鸭子有各种行为,比如叫、飞行等等。 2)显示鸭子的信息

    海仔
  • 浅谈JAVA设计模式之——策略模式(Strategy)

    定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

    冰河
  • Java单体应用 - 架构模式 - 03.设计模式-23.策略模式

    原文地址:http://www.work100.net/training/monolithic-architecture-design-patterns-str...

    光束云
  • Python 中的设计模式详解之:策略模式

    策略模式:定义一系列算法,把它们一一封装起来,并且使它们之间可以相互替换。此模式让算法的变化不会影响到使用算法的客户。

    丹枫无迹
  • Java常用设计模式--策略模式(Strategy Pattern)

    在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

    gang_luo
  • php设计模式之策略模式应用案例详解

    策略模式定义一系列的算法,将每个算法封装起来,并让它们可以相互装换。策略模式让算法独立于使用它的客户而独立变化。

    砸漏
  • 工作中的设计模式 —— 策略模式

    策略模式是一种行为设计模式,它能让你定义一系列算法,并将每种算法分别放入独立的类中,以使算法的对象能够相互替换。

    程序员小航
  • java设计模式之状态模式,策略模式的孪生兄弟

    状态模式(State Pattern)中,类的行为是基于它的状态改变的,状态之间的切换,在状态A执行完毕后自己控制状态指向状态B,状态模式是不停的切换状态执行,...

    用户4361942
  • 设计模式:Python策略模式实现,真实项目背景

    嘉美伯爵
  • 工作中常见的设计模式-策略模式

    最近准备学习下之前项目中用到的设计模式,这里代码都只展示核心业务代码,省略去大多不重要的代码。

    一枝花算不算浪漫
  • 【“别跟我不会”系列】Java设计模式之策略模式

    一直以来,笔主想写关于设计模式的系列文章与大家进行交流,但碍于自己经验上尚浅,无法将此讲解透彻,闹了笑话。但千里之行,始于足下,我决定将我自己的工作中我用到的设...

    23号杂货铺
  • 设计之禅——灵活的策略模式

    在平时生活中当我们想要做一件事的时候往往会有许多的途径和方法,像我们去公司上班,可以走路去,也可以骑车或者开车去;还有像吃饭,我们可以选择自己做饭吃,也可以出去...

    夜勿语
  • PHP设计模式之策略模式(Strategy)入门与应用案例详解

    本文实例讲述了PHP设计模式之策略模式(Strategy)入门与应用。分享给大家供大家参考,具体如下:

    砸漏
  • 设计模式(2)-策略模式之多用组合少用继承

    首先看一下策略模式的意图 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。 结构 ? 适用性 许多相关...

    cloudskyme
  • Java设计模式之适配器设计模式(项目升级案例)

     今天是我学习到Java设计模式中的第三个设计模式了,但是天气又开始变得狂热起来,对于我这个凉爽惯了的青藏人来说,又是非常闹心的一件事儿,好了不管怎么样,目标...

    赵小忠

扫码关注云+社区

领取腾讯云代金券