工作忙完一些,刚好有空,就准备继续写一下设计模式的学习总结。
今天写的第一个设计模式是策略模式。
策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
先举个代码的例子(举例比较渣渣请原谅)
1、定义一个水果抽象类Fruit
package head_first.strategy.self;
public abstract class Fruit {
GrowUp grow; //长大的行为
Plant plant; //种植的行为
/**
* 水果的通用方法
*/
public void canBeEat(){
System.out.println("I can be eat!");
}
public abstract void display(); //子类实现各种水果的特征
/**
* 引入长大的实现类,其目的是为了实现在运行过程中可以改变长大的行为
* @param grow
*/
public void setGrowUp(GrowUp grow){
this.grow = grow;
}
/**
* 同上
* @param plant
*/
public void setPlant(Plant plant){
this.plant = plant;
}
public void performGrow(){
grow.growUp();
}
public void perfromPlant(){
plant.plant();
}
}
GrowUp(长大)和Plant(种植)是水果行为两个抽象(接口),代码为:
package head_first.strategy.self;
public interface Plant {
public void plant();
}
package head_first.strategy.self;
public interface GrowUp {
public void growUp();
}
实现了一个具体水果类Apple
package head_first.strategy.self;
public class Apple extends Fruit {
public Apple(){
//实现了苹果的两个特殊行为
grow = new SlowGrowUp();
plant = new DeepPlant();
}
public void display() {
System.out.println("I am a apple!");
}
}
和草莓具体类
package head_first.strategy.self;
public class Strawberry extends Fruit {
public Strawberry() {
// 实现了草莓的两个特殊行为
grow = new QuickGrowUp();
plant = new SimplePlant();
}
public void display() {
System.out.println("I am strawberry");
}
}
接下来是水果的两种行为长大和种植的具体类:
package head_first.strategy.self;
public class SlowGrowUp implements GrowUp {
public void growUp() {
System.out.println("grow up slow");
}
}
package head_first.strategy.self;
public class QuickGrowUp implements GrowUp {
public void growUp() {
System.out.println("grow up quick");
}
}
package head_first.strategy.self;
public class SimplePlant implements Plant {
public void plant() {
System.out.println("Simple plant!");
}
}
package head_first.strategy.self;
public class DeepPlant implements Plant {
public void plant() {
System.out.println("Deep plant!");
}
}
另外定义一个奔跑的行为(成为食人果啦,哈哈~~)RunPlant :
package head_first.strategy.self;
public class RunPlant implements Plant {
public void plant() {
System.out.println("I am a runing fruit!!!");
}
}
最后是测试类
package head_first.strategy.self;
public class FruitTest {
public static void main(String[] args) {
//apple的正常行为
Apple apple = new Apple();
apple.performGrow();
apple.perfromPlant();
Strawberry straw = new Strawberry();
straw.perfromPlant();
//把草莓的种植行为在运行时动态改为喷跑的行为
straw.setPlant(new RunPlant());
straw.perfromPlant();
}
}
测试类输出的结果:
grow up slow
Deep plant!
Simple plant!
I am a runing fruit!!!
例子大概就是这样了。
Fruit抽象类定义了水果的抽象,canBeEat()方法是水果的通用方法,把实现写在Fruit类中,也可以加上final使其避免被子类覆盖。
GrowUp和Plant是对水果的两个可以变化的行为的封装,这样水果类获取的是行为的抽象引用,是针对抽象的编程,可以使水果类与起行为的实现解耦和了,更利于其扩展。
display()方法在Fruit中定义为抽象方法,在各个子类中自己实现自己的独特外貌。
setGrowUp(GrowUp grow)和setPlant(Plant plant)方法提供了运行中动态改变水果行为的能力。也是对行为实现解耦的一种体现。
在设计模式的学习中可以隐藏着许多代码设计原则:
1、封装变化。
上面水果的长大和种植的行为根据不同水果是变化的,所以我们把它封装成抽象,有利于解耦和扩展。
2、多用组合,少用继承。
使用组合建立系统具有很大的弹性,不仅可以将算法族封装成类,更可以在运行时动态的改变行为,只要这些行为都符合定义接口的标准即可。Fruit类中GrowUp和Plant就是组合。
3、针对接口编程,不针对实现编程
针对接口编程后,客户就不需要知道实现的具体细节了,完成了解耦。
对于策略模式就差不多这样吧,有很多没有讲清楚的地方,跟大家互相学习。培养设计模式的思维方式。