一、前言
策略模式定义了算法族,分别封装起来,让他们之间可以相互替代,此模式让算法的变化独立于使用算法的客户。
在Head First设计模式第一章中,提出了”策略“这一设计模式,并以鸭子为例来讲解之。
针对不会飞的鸭子和不会呱呱叫的鸭子,提出了将行为和呱呱叫行为单独封装成一个接口。而将几乎固定不变的行为和属性封装在超类(虚基类)中,这其中体现了几个设计原则和设计思想。
OO基础:抽象,封装,多态,继承。
OO原则:封装变化;多用组合,少用继承;针对接口编程,不针对实现编程。
OO模式:策略模式----定义算法族,分别封装起来,让他们直接可以互相替换,此模式让算法的变化独立于使用算法的客户。
(1)封装变化
鸭子的飞行行为和呱呱叫行为都是变化的,将它们封装到两个行为接口类中,在以后可以轻易地改动或扩充行为而不影响其他部分。
(2)少用继承,多用组合
继承是“is-a”的关系,组合是"has-a"的关系。继承可以看作是一种亲属关系,而组合则是一种朋友的关系。因此不难理解,当父类中的方法属性需要改变时,将会牵涉到众多的子类,而朋友则没有那么多牵涉关系。
Duck内部持有FlyBehavior和QuackBehavior的引用,鸭子的行为是和行为对象“组合”而来的,使系统具有很大的弹性,并且可以动态设置行为。
(3)针对接口编程,不针对实现编程
Duck内部的属性flyBehavior和quackBehavior都是接口类型的,将具体行为与鸭子类分离开来,实现了解耦,并且我们能够在运行时通过多态的魔力动态地指定行为的不同的实现类。
二、动作冒险游戏的实现
现在将以第一章设计谜题中的动作冒险游戏为例,体现出“策略”模式的设计理念。
可以看到,其中我将武器类声明为接口类,character设为超类,然后具体的武器,人物都从这两者之中继承并实现。
因为有的角色可能并不使用武器,或者说武器的用法比较奇特(比如说魔法),因此将武器单独声明为一个接口,这正体现了“策略”模式的封装变化等设计理念。
UML图
导出的UML图如下所示…这里是使用了intellij导出UML的图。(没记错的话,因为这是我19年5月完成的)
Weapon.java
package test01;
// 武器接口
public interface Weapon {
public void fight();
public String getName();
}
// 小刀类
class Knife implements Weapon {
private String name = "Knife";
public void fight(){
System.out.println("用刀砍!");
}
public String getName() {
return this.name;
};
}
// 弓箭
class Bow implements Weapon {
private String name = "Bow";
public void fight(){
System.out.println(("用弓!"));
}
public String getName() {
return this.name;
};
}
// 弩箭
class Arrow implements Weapon{
private String name = "Arrow";
public void fight(){
System.out.println("用箭!");
}
public String getName() {
return this.name;
};
}
// 拔剑
class Sword implements Weapon{
private String name = "Sword";
public void fight(){
System.out.println("用剑刺!");
}
public String getName() {
return this.name;
};
}
// 斧头
class Axe implements Weapon{
private String name = "Axe";
public void fight(){
System.out.println("用斧子剁!");
}
public String getName() {
return this.name;
};
}
Character.java
package test01;
public abstract class Character {
public String name; // 名字
public Weapon aWeapon; // 武器
Character(){ }
Character(String name,Weapon aWeapon){
System.out.println("Constructing an Character。。。\n");
this.name = name;
this.aWeapon = aWeapon;
}
public abstract void skill(); // 技能
public String getName(){
return name;
}
public void usingWeapon(){
System.out.println("\n******用武器******\n");
System.out.println(this.getName() + "are using Weapon!\n");
this.aWeapon.fight(); // 多态性, 父类调用子类方法
System.out.println("\n*****************\n");
}
public void changeWeapon(Weapon newWeapon){
System.out.println("\n******换武器*******\n");
System.out.println("原武器:" + this.aWeapon.getName());
this.aWeapon = newWeapon;
System.out.println("新武器:" + this.aWeapon.getName());
System.out.println("\n*****************\n");
}
}
class King extends Character{
King(String name, Weapon aWeapon){
super(name, aWeapon);
}
public void skill() { // king技能
System.out.println("King use skill!");
}
}
class Queen extends Character{
Queen(String name, Weapon aWeapon){
super(name, aWeapon);
}
public void skill() { // king技能
System.out.println("Queen use skill!");
}
}
class Troll extends Character{
Troll(String name, Weapon aWeapon){
super(name, aWeapon);
}
public void skill() { // king技能
System.out.println("Troll use skill!");
}
}
class Knight extends Character {
Knight(String name, Weapon aWeapon){
super(name, aWeapon);
}
public void skill() { // king技能
System.out.println("Knght use skill!");
}
}
ActionGame.java
package test01;
public class ActionGame {
public static void main(String arg[]){
Knife kn = new Knife();
Bow bo = new Bow();
Arrow ar = new Arrow();
Sword sw = new Sword();
Axe ax = new Axe();
King king = new King("秦始皇", kn);
Queen queen = new Queen("伊丽莎白", sw);
Troll troll = new Troll("岳云鹏", ar);
Knight knight = new Knight("亚历山大", ax);
System.out.println("------------------");
king.usingWeapon();
queen.usingWeapon();
troll.usingWeapon();
knight.usingWeapon();
System.out.println("------------------");
System.out.println("骑士变换了武器");
knight.changeWeapon(bo);
knight.usingWeapon();
}
}
运行结果
