策略模式的定义:
定义了算法簇,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
首先看策略模式的定义,
算法簇也就是一群实现了同一个接口的实现类,
让它们之间可以相互替换的意思也就是要针对接口编程,而不是针对类编程。
此模式让算法的变化独立于使用算法的客户是说,采用何种算法只取决于调用者。
现在说说例子:
一个格斗游戏,角色类Fighter可以使用很多武器,不同武器攻击力以及特殊效果不同,比如使用剑能有一定几率造成额外伤害,斧子有一定几率造成双倍伤害。如果不使用模式的情况下实现这个游戏的话,Fighter就应该有一些方法:attackWithSword(),attackWithAxe()。如果剑类武器又有:铁剑、霜之哀伤,又要为这两把剑写两个方法。如果有1000个武器呢?(当然实现这个的方法还有很多,尤其是笨方法很多。。。)
为了避免以上情况,我们定义一个接口:
package com.Weapon;
import com.fighter.Fighter;
public interface WeaponBehavior {
public void attackWithWeapon(Fighter fighter);
public String getName();
public void setName(String name);
}
让所有武器去实现这个接口,所有实现了这个接口的类,都叫算法簇。
现在,抽象类剑,实现了这个接口,这里剑是一个种类,而不是一个具体武器,所以是抽象类:
package com.Weapon;
import java.util.Random;
import com.fighter.Fighter;
//剑类武器有一定几率造成额外的伤害
public abstract class Sword implements WeaponBehavior {
// 普通伤害
int damage;
String name;
// 特殊攻击的伤害
int specialDamage;
// 特殊攻击的触发几率
int probability;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDamage() {
return damage;
}
public void setDamage(int damage) {
this.damage = damage;
}
@Override
public void attackWithWeapon(Fighter fighter) {
normalAttack(fighter);
specialAttack(fighter);
}
protected void normalAttack(Fighter fighter) {
System.out.println("用" + this.getName() + "对" + fighter.getName()
+ "造成了" + this.getDamage() + "基本伤害。");
fighter.loseLife(this.getDamage());
}
protected void specialAttack(Fighter fighter) {
Random r = new Random();
int i = r.nextInt(100);
if (i < this.probability) {
System.out.println(this.getName() + "触发了特殊效果,对" + fighter.getName()
+ "造成了" + this.specialDamage + "点额外伤害。");
fighter.loseLife(this.specialDamage);
}
}
}
剑这个类里定义了伤害值,特殊攻击的伤害值,特殊攻击的触发几率,并且在这里定义了特殊攻击的算法。这样做有什么好处呢?看了子类就知道了:
package com.Weapon;
import com.fighter.Fighter;
/*
* 霜之哀伤,攻击力100,有百分之50造成额外的50点伤害。
* */
public class Frostmourne extends Sword {
public Frostmourne()
{
this.setName("霜之哀伤");
this.setDamage(100);
specialDamage=50;
probability=50;
}
@Override
protected void specialAttack(Fighter fighter) {
super.specialAttack(fighter);
}
}
大家看到了,子类很简单,只要定义一下名字,伤害,以及特殊攻击伤害、特殊攻击几率而已,因为具体算法实现已经由父类实现了。
同样的,还有斧类武器:
package com.Weapon;
import java.util.Random;
import com.fighter.Fighter;
//斧类武器有一定几率造成双倍伤害
public abstract class Axe implements WeaponBehavior {
// 普通伤害
int damage;
String name;
// 特殊攻击的伤害
int specialDamage;
// 特殊攻击的触发几率
int probability;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDamage() {
return damage;
}
public void setDamage(int damage) {
this.damage = damage;
}
@Override
public void attackWithWeapon(Fighter fighter) {
normalAttack(fighter);
specialAttack(fighter);
}
protected void normalAttack(Fighter fighter) {
System.out.println("用" + this.getName() + "对" + fighter.getName()
+ "造成了" + this.getDamage() + "基本伤害。");
fighter.loseLife(this.getDamage());
}
protected void specialAttack(Fighter fighter) {
Random r = new Random();
//斧子有一定几率造成双倍伤害
this.specialDamage=damage*2;
int i = r.nextInt(100);
if (i < this.probability) {
System.out.println(this.getName() + "触发了特殊效果,对" + fighter.getName()
+ "造成了" + this.specialDamage + "点额外伤害。");
fighter.loseLife(this.specialDamage);
}
}
}
package com.Weapon;
import com.fighter.Fighter;
/*
* 公正使者,攻击力100,有百分之30几率造成双倍伤害。
* */
public class Axe1 extends Axe {
public Axe1()
{
this.setName("公正使者");
this.setDamage(100);
probability=30;
}
@Override
protected void specialAttack(Fighter fighter) {
super.specialAttack(fighter);
}
}
武器就写这么多吧,现在看看Fighter,它就是策略模式定义中的
使用算法的客户
package com.fighter;
import com.Weapon.WeaponBehavior;
public class Fighter {
private int life;
private String name;
private WeaponBehavior weapon;
public Fighter(String name,WeaponBehavior weapon)
{
this.weapon=weapon;
this.name=name;
this.life=1000;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void hit(Fighter fighter)
{
this.weapon.attackWithWeapon(fighter);
}
public int getLife() {
return life;
}
private void setLife(int life) {
this.life = life;
}
public WeaponBehavior getWeapon() {
return weapon;
}
public void setWeapon(WeaponBehavior weapon) {
this.weapon = weapon;
}
public void loseLife(int damage)
{
this.setLife(this.getLife()-damage);
}
public void changeWeapon(WeaponBehavior weapon)
{
System.out.println(this.getName()+"装备了"+weapon.getName());
this.setWeapon(weapon);
}
}
可以看到,Fighter攻击的时候只是去调用了自身武器的attackWithWeapon(Fighter fighter)方法。这就证实了策略模式的定义,
定义了算法簇,分别封装起来,让他们之间可以相互替换,这些武器就是算法簇,使用者只要更换掉自己想要使用的实现类就行了,在调用算法的时候,依然只是调用算法实现的接口。
看下测试类
package com.main;
import com.Weapon.Axe1;
import com.Weapon.Frostmourne;
import com.fighter.Fighter;
public class Main {
public static void main(String[] args) {
Fighter player=new Fighter("player",new Frostmourne());
Fighter computer=new Fighter("computer",new Frostmourne());
player.hit(computer);
System.out.println(computer.getName()+"还剩下"+computer.getLife()+"生命");
player.hit(computer);
System.out.println(computer.getName()+"还剩下"+computer.getLife()+"生命");
//这里更换了算法(武器)
player.changeWeapon(new Axe1());
player.hit(computer);
System.out.println(computer.getName()+"还剩下"+computer.getLife()+"生命");
player.hit(computer);
System.out.println(computer.getName()+"还剩下"+computer.getLife()+"生命");
player.hit(computer);
System.out.println(computer.getName()+"还剩下"+computer.getLife()+"生命");
player.hit(computer);
System.out.println(computer.getName()+"还剩下"+computer.getLife()+"生命");
}
}
测试结果:
用霜之哀伤对computer造成了100基本伤害。
霜之哀伤触发了特殊效果,对computer造成了50点额外伤害。
computer还剩下850生命
用霜之哀伤对computer造成了100基本伤害。
霜之哀伤触发了特殊效果,对computer造成了50点额外伤害。
computer还剩下700生命
player装备了公正使者
用公正使者对computer造成了100基本伤害。
computer还剩下600生命
用公正使者对computer造成了100基本伤害。
公正使者触发了特殊效果,对computer造成了200点额外伤害。
computer还剩下300生命
用公正使者对computer造成了100基本伤害。
computer还剩下200生命
用公正使者对computer造成了100基本伤害。
computer还剩下100生命