本次博客将对java中23种设计模式展开说明,首先说下什么是设计模式。
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。他不是一套集成的框架,或者jar包。而是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。遇到与之有关的问题时,不同再去自己想解决办法,按照某种模式去做即可,为开发提供了大量的便捷。
本篇的主要内容为策略模式,策略模式是指对一系列的算法定义,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。下面进行一个案例的模拟,举一个例人群的例子:
1.现在有不同的人群,分别为中国救生员、美国教师…,他们均具有eatFood(),sleep()的功能,并功能相同,还均具备speakLanguage()功能,但功能不同,怎么设计?
2.这时候想到了继承。继承可以解决代码复用的问题,大大的提高了开发效率,进而向上抽取出父类Person(), 父类中有具体的eatFood()与sleep() ,和抽象方法speakLanguage()
//父类
public abstract class Person {
public void eatFood(){
System.out.println("我会吃食物...");
}
public void sleep(){
System.out.println("我会睡觉...");
}
public abstract void speakLanguage();
}
//子类一
public class ChineseLifeguard extends Person{
@Override
public void speakLanguage(){
System.out.println("我说汉语");
}
}
//子类二
public class AmericanTeacher extends Person {
@Override
public void speakLanguage() {
System.out.println("我说英语");
}
}
3.目前的需求解决了,但突然有一天有新增一个需求,想为Person()的一些子类添加一个swim(),smoke()功能怎么办?
利用oop思想几种解决方案:
(1)直接定义在子类中,谁需要此功能,谁加入此功能,但是相同的代码写多遍,不合理(有可能需要此功能的子类共有几十个)。
(2)定义为父类中成员方法,但导致所有子类全部拥有了此功能,即使某些子类不需要,不合理。
(3)定义为父类的抽象方法,子类继承父类时,需要用此功能则重写,但仍旧是相同的代码写多遍,不合理。
综上所述,几种方案均不太合理,怎么办呢?这是就可以利用策略模式去解决此问题。
4.利用策略模式重构代码
(1)分析需求,那些功能可变,那些功能不可变,答:可变的为swim(),smoke()方法(speakLanguage()暂时省略),不同的子类有不同的表现。不可变的为eatFood(),sleep()方法,所有Person()的子类表现均一致,那么把可变的功能抽象成接口。创建功能接口ISwim()与ISmoke()
public interface ISwim {
void swim();
}
public interface ISmoke {
void smoke();
}
(2)创建接口的实现类,分别描述此功能的实现。
ISwim接口的实现类:
//不会游泳
public class NotSwim implements ISwim {
@Override
public void swim() {
System.out.println("我不会游泳!");
}
}
//游泳非常棒
public class GoodSwim implements ISwim {
@Override
public void swim() {
System.out.println("我游泳非常好!");
}
}
//还可以新增一种实现:会游泳,游的不好
public class BadSwim implements ISwim {
@Override
public void swim() {
System.out.println("我游泳比较差!");
}
}
ISmoke接口的实现类:
//会吸烟
public class CanSmoke implements ISmoke {
@Override
public void smoke() {
System.out.println("我会吸烟!");
}
}
//不会吸烟
public class NotSmoke implements ISmoke {
@Override
public void smoke() {
System.out.println("我不会吸烟");
}
}
(3).修改父类Person()
//父类
public abstract class Person {
ISwim swim; //行为对象,等待子类实例化
ISmoke smoke; //行为对象,等待子类实例化
//eatFood()功能不变
public void eatFood() {
System.out.println("我会吃食物...");
}
//sleep()功能不变
public void sleep() {
System.out.println("我会睡觉...");
}
//添加swim方法,具体的实现根据子类的swim对象不用而不同
public void swim(){
swim.swim();
}
// 同上
public void smoke(){
smoke.smoke();
}
}
(4)重点来了,如何去定义子类?
public class ChineseLifeguard extends Person{
public ChineseLifeguard(){
this.swim = new GoodSwim(); //游泳非常棒
this.smoke = new NotSmoke(); //不会吸烟
}
}
public class AmericanTeacher extends Person {
public AmericanTeacher(){
this.swim = new NotSwim(); //不会游泳
this.smoke = new CanSmoke(); //会吸烟
}
}
在新增一个子类JapanBaby :
public class JapanBaby extends Person {
public JapanBaby(){
this.swim = new BadSwim(); //刚出生的婴儿会游泳,游泳不怎么好
this.smoke = new NotSmoke(); // 不会吸烟
}
}
这样在实例化子类的时候,就已经指明swim()与smoke() 的具体实现,提高了扩展性,减少了代码量。
最后进行测试:
public class TestPerson {
public static void main(String[] args) {
System.out.println("美国教师:");
AmericanTeacher americanTeacher = new AmericanTeacher();
americanTeacher.eatFood();
americanTeacher.sleep();
americanTeacher.swim();
americanTeacher.smoke();
System.out.println("...........................................");
System.out.println("中国救生员:");
ChineseLifeguard chineseLifeguard = new ChineseLifeguard();
chineseLifeguard.eatFood();
chineseLifeguard.sleep();
chineseLifeguard.swim();
chineseLifeguard.smoke();
System.out.println("...........................................");
System.out.println("日本婴儿:");
JapanBaby japanBaby = new JapanBaby();
japanBaby.eatFood();
japanBaby.sleep();
japanBaby.swim();
japanBaby.smoke();
}
}
结果: