设计模式
含义: 是人们在面对同类型软件工程设计问题总结出来的一些有用的经验!!!
模式不是代码, 而是某类问题的通用设计解决方案. 嗯, 你可以理解是解决一种类型问题的套路.
目的: 是软件工程在维护性, 扩展性, 变化性, 复杂度方面成为 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 同理啦~(是不是没有坑了)
这样做的好处是:
新增行为简单, 行为类更好得复用, 组合更方便, 竟可以有继承带来代码复用的好处, 又没有挖坑.
策略模式的定义:
分别封装行为接口, 实现算法族, 父类里放行为接口对象, 在子类的构造方法里具体实现设定行为对象.
策略模式的原则:
分离变化部分, 封装接口, 基于接口编程各种行为. 此模式让算法的变化独立与算法的使用者.(好官方呀!!!)
这是本人学习过程中自己举例理解策略模式的例子, 可能存在很多的局限性, 若有不恰当的地方, 希望小伙伴指出讨论, 谢谢啦~
来源: http://www.jianshu.com/p/0746de0b1f61