设计模式
含义:是人们在面对同类型软件工程设计问题总结出来的一些有用的经验!!!
模式不是代码,而是某类问题的通用设计解决方案。嗯,你可以理解是解决一种类型问题的套路。
目的:是软件工程在维护性,扩展性,变化性,复杂度方面成为O(n).
面向对象(OO)是原则 ,设计模式是解决问题的方法。
一.策略模式
1.从项目“记录自己的朋友行为”开始。
(1)我们先从面向对象的角度设计这个项目,朋友父类
//首先我们把自己的朋友共同有的性质,封装成一个父类
package com.java.stimulateFriend.oo;
public abstract class Friend {
//构造方法
public Friend() {}
//会讲普通话
public void speaking() {
System.out.println("我会讲普通话!!");
}
//会吃
public void eatting() {
System.out.println("我是吃货!!!");
}
//主修科目 让子类具体实现 因为主修科目不同
public abstract void subject();
}
然后我有俩个朋友 分别继承friend
//一个friend叫keen
package com.java.stimulateFriend.oo;
public class Keen extends Friend {
@Override
public void subject() {
System.out.println("我主修计算机");
}
}
//另外一个friend叫spohie.
package com.java.stimulateFriend.oo;
public class Sophie extends Friend{
@Override
public void subject() {
System.out.println("我主修英语");
}
}
测试类
package com.java.stimulate.test;
import com.java.stimulateFriend.oo.Keen;
import com.java.stimulateFriend.oo.Sophie;
public class test {
public static void main(String[] args) {
//创建对象
Sophie sophie = new Sophie();
Keen keen = new Keen();
//调用方法
sophie.subject();
sophie.eatting();
sophie.speaking();
keen.subject();
keen.eatting();
keen.speaking();
}
}
//output:
我是sophie,主修英语
是个吃货!!!
会讲普通话!!
我是keen,我主修计算机
是个吃货!!!
会讲普通话!!
(1)新的需求:然而随着朋友的长大,她们又学会了一项新技能,会跳舞。(此时你会觉得继承多好呀,增加代码的复用,嗯,确实有时候挺好的!)
用面向对象的思维,我们会直接在Friend超类中增加一项跳舞的技能
package com.java.stimulateFriend.oo;
public abstract class Friend {
...
...
public void dancing()
{
System.out.println("会跳舞了!!!");
}
}
(2)新的需求:然而在我的成长过程中,我又交一个新的盘友了,他会唱歌哦,很好听!!!
那么问题来了,我在增加这个朋友的时候,如果我把唱歌这项功能放在Friend超类里,是不是所有的朋友都特别会唱歌了???可是现实中我的其他朋友是音痴呀,这是不是就不科学了呢!!!!然后你想,在不会唱歌的朋友那里进行方法的覆盖,可是盆友有很多的时候,是不是就增加了很多代码量了呀!!!不划算,好累。
此时我们又会想到让这个朋友自己实现这个方法就好了,不加超类,不就完了么!!!可是我以后还会通过他认识更多会唱歌的盆友呀,又在会唱歌的朋友那一个一个的实现吗???是不是很麻烦???而且假如这个朋友也不会跳舞耶!!!咋整???
2.在这里,我们可以发现:
继承问题:在对类的局部改动,尤其是超类(父类()的局部改动,会影响其他子类,影响会有溢出效益。
换句话说就是:超类挖的一个坑,每个子类都要来填,而且这个坑,有的子类不需要,此时复杂度大大的增加了. O(N^2)
3.此时救星来了(策略模式!!!)
需要新的设计模式,应对项目的扩展性,降低复杂度。下面就开始学习第一个设计模式 ———— 策略模式。
(1)分析项目中变化与不变化的部份,提取变化的部分,抽象成接口+实现;
接着上面,我们想哪些行为会是以后变化的,比如:唱歌,跳舞....
此时我们抽取出来 ,用接口实现
1.创建一个唱歌的接口
package com.java.friendsingbehavior;
public interface SingBehavior {
void singing();
}
2.实现唱歌的行为
//会唱歌GoodSing
package com.java.friendsingbehavior;
public class GoodSing implements SingBehavior {
@Override
public void singing() {
System.out.println("我唱歌非常棒!!!");
}
}
//不会唱歌
package com.java.friendsingbehavior;
public class BadSing implements SingBehavior {
@Override
public void singing() {
System.out.println("我是音痴!");
}
}
3.创建跳舞的接口
package com.java.friend.dancingbehavior;
public interface DancingBehavior {
void dancing();
}
4.实现跳舞的行为
//BadDancing
package com.java.friend.dancingbehavior;
public class BadDancing implements DancingBehavior{
@Override
public void dancing() {
System.out.println("my dancing is so bad!!!");
}
}
//Gooddancing
package com.java.friend.dancingbehavior;
public class Gooddancing implements DancingBehavior {
@Override
public void dancing() {
System.out.println("my dancing is good !!");
}
}
5.朋友类(父类)
package com.java.stimulate.Friend;
import com.java.friend.dancingbehavior.DancingBehavior;
import com.java.friendsingbehavior.SingBehavior;
public abstract class Friend {
SingBehavior singbehavor;
DancingBehavior dancingbehavior;
// 构造方法
public Friend() {
}
// 会讲普通话
public void speaking() {
System.out.println("会讲普通话!!");
}
// 会吃
public void eatting() {
System.out.println("是个吃货!!!");
}
// 主修科目
public abstract void subject();
// 在这里我们就不用实现唱歌的方法了,直接用接口方法
public void singing() {
singbehavor.singing();
}
// 跳舞同理
public void dancing() {
dancingbehavior.dancing();
}
//设置setter属性以便以后动态地改变这些行为
public void setSingbehavor(SingBehavior singbehavor) {
this.singbehavor = singbehavor;
}
public void setDancingbehavior(DancingBehavior dancingbehavior) {
this.dancingbehavior = dancingbehavior;
}
}
6.(1)我的朋友keen
package com.java.stimulate.Friend;
import com.java.friend.dancingbehavior.*;
import com.java.friendsingbehavior.*;
public class Keen extends Friend {
public Keen() {
singbehavor = new BadSing();
dancingbehavior = new Gooddancing();
}
@Override
public void subject() {
System.out.println("我是keen,学计算机的!!");
}
}
6.(2)我的朋友sophie
package com.java.stimulate.Friend;
import com.java.friend.dancingbehavior.*;
import com.java.friendsingbehavior.*;
public class Sophie extends Friend{
public Sophie() {
singbehavor = new GoodSing();
dancingbehavior = new BadDancing();
}
@Override
public void subject() {
System.out.println("我是Sphoie,我学英语!!");
}
}
7.测试类:
package com.java.stimulate.test;
import com.java.friend.dancingbehavior.*;
import com.java.stimulate.Friend.*;
public class test_01 {
public static void main(String[] args) {
//创建对象
Friend sophie = new Sophie();
Friend keen = new Keen();
sophie.subject();
sophie.eatting();
sophie.speaking();
sophie.dancing();
//在这里我们可以动态的改变跳舞唱歌的行为,
//因为在之前我们设计setter属性
//System.out.println("change letter!");
//sophie.setDancingbehavior(new Gooddancing());
sophie.dancing();
sophie.singing();
keen.subject();
keen.eatting();
keen.speaking();
keen.dancing();
keen.singing();
}
}
output:
我是Sphoie,我学英语!!
是个吃货!!!
会讲普通话!!
my dancing is so bad!!!
//change letter!
//my dancing is good !!
我唱歌非常棒!!!
我是keen,学计算机的!!
是个吃货!!!
会讲普通话!!
my dancing is good !!
我是音痴!
说明:此时就算keen没有唱歌的能力,我们在keen类里(子类)不创建singbehavor = new GoodSing();不实现也不会报错的,sophie同理啦~(是不是没有坑了)
这样做的好处是:
新增行为简单,行为类更好得复用,组合更方便,竟可以有继承带来代码复用的好处,又没有挖坑。
策略模式的定义:
分别封装行为接口,实现算法族,父类里放行为接口对象,在子类的构造方法里具体实现设定行为对象。
策略模式的原则:
分离变化部分,封装接口,基于接口编程各种行为。此模式让算法的变化独立与算法的使用者。(好官方呀!!!)
网友评论