Java 抽象类中变与不变的行为设计
2017-10-08 15:50
162 查看
问题提出:
在实际业务开发过程中,对于同样一种事件可能有不同的处理行为,而且在开发完成之后,后期可能会添加新的处理行为,如何在不影响旧有的业务代码增加新的行为是本文需要探讨的问题。
举个栗子:
有个模拟鸭子游戏,在游戏中有各种鸭子,鸭子可以一边游泳戏水,一边呱呱叫,然后我们还要展示鸭子的颜色等等。
已知条件:
1、所有的鸭子都会游泳;
2、有的鸭子会呱呱叫,有的鸭子不会呱呱叫;
3、后期可能会添加其他行为。
思路分析:
通常对于既有变化的行为和不变化的行为,我们通过一个抽象类来实现,在抽象类中将不变的游泳实现出来,这样所有继承该抽象类的类将不需要再去重复该代码,对于不确定的行为呱呱叫写一个抽象方法进行,具体的实现由它所继承的类来实现。
可知:上述将所有的行为都通过方法进行实现。
缺点:如果要添加一个行为(该行为具有不确定性),则在抽象类中添加一个抽象方法,所有实现该抽象类的类都要去实现该接口(注意:抽象类也是接口的一种,可以作为继承类的父类),而有些实现该抽象类的类可能并不需要该行为。
解决办法:区分出可变行为,并将可变行为封装成接口类,在抽象类,通过字段声明(实现has a 而不是 is a),以及相应的方法来表现该行为,行为的具体实现类,在具体实现抽象类中的类中进行调用。这样的有点,后期在增加新的行为时,不会影响到旧有代码的逻辑,达到低耦合的目的。
举个栗子:
Duck.java类
分析:
在Duck.java 类这中,游泳行为swim()是鸭子实现类共有的特征且一定会游泳,因此,将其实现出来。而display()是所有鸭子的共有特征,但是不同鸭子的行为不一样,因此,将其抽象出来,所有继承该抽象方法的鸭子都要实现该方法。鸭子的飞行行为和叫的行为,并不是所有鸭子的共有特征,因此,将其声明为接口,这样,所有实现该抽象类的类可以按需要不要去关心鸭子的飞行和叫的行为,达到低耦合的目的。比如,此时,如果有些鸭子需要跳舞的行为,则可以同样添加一个跳舞的接口。
补充:
关于接口中的行为有两种:
一种是获取接口的行为,如:performFly();
另一种是改变接口的行为,如:setFly() (改变行为实现对鸭子的行为进行动态设置)。
FlyBehavior.java类:
两个实现FlyBehavior.java类如下:
Fly.java类:
NoFly.java 类:
QuackBehavior.java类:
两个实现QuackBehavior.java类如下:
Quack.java 类:
NoQuack.java 类:
一个Duck.java的实现类如下:
MallardDuck.java 类:
分析:
上述实现类对于Duck.java的实现类中,在构造函数中实例化鸭子的飞行行为和叫的行为。另外:对于鸭子的飞行行为和叫的行为可以在后期通过set函数进行更改。
实际调用的main方法如下:
输出:
I can fly!
I can't fly!
实现了运行时动态更改鸭子的飞行行为。
总结分析:
抽象类中的三种行为:
1、所有继承该抽象类都会有该行为,且行为都一样。(具体方法实现)
2、所有继承该抽象类都会有该行为,但行为都不一样。(抽象方法)
3、只有部分继承该抽象类会有该行为。(面向接口编程)
使用模式最好的方式是:“把模式装进脑子里,然后在你的设计和已有的应用中,寻找何处可以使用它们。”以往是代码复用,现在是经验复用。
OO原则:
1)封装变化(代码复用,低耦合)
2)多用组合,少用继承(推荐has a ,少用is a)
3)针对接口编程,不针对实现编程
在实际业务开发过程中,对于同样一种事件可能有不同的处理行为,而且在开发完成之后,后期可能会添加新的处理行为,如何在不影响旧有的业务代码增加新的行为是本文需要探讨的问题。
举个栗子:
有个模拟鸭子游戏,在游戏中有各种鸭子,鸭子可以一边游泳戏水,一边呱呱叫,然后我们还要展示鸭子的颜色等等。
已知条件:
1、所有的鸭子都会游泳;
2、有的鸭子会呱呱叫,有的鸭子不会呱呱叫;
3、后期可能会添加其他行为。
思路分析:
通常对于既有变化的行为和不变化的行为,我们通过一个抽象类来实现,在抽象类中将不变的游泳实现出来,这样所有继承该抽象类的类将不需要再去重复该代码,对于不确定的行为呱呱叫写一个抽象方法进行,具体的实现由它所继承的类来实现。
可知:上述将所有的行为都通过方法进行实现。
缺点:如果要添加一个行为(该行为具有不确定性),则在抽象类中添加一个抽象方法,所有实现该抽象类的类都要去实现该接口(注意:抽象类也是接口的一种,可以作为继承类的父类),而有些实现该抽象类的类可能并不需要该行为。
解决办法:区分出可变行为,并将可变行为封装成接口类,在抽象类,通过字段声明(实现has a 而不是 is a),以及相应的方法来表现该行为,行为的具体实现类,在具体实现抽象类中的类中进行调用。这样的有点,后期在增加新的行为时,不会影响到旧有代码的逻辑,达到低耦合的目的。
举个栗子:
Duck.java类
public abstract class Duck { QuackBehavior quackBehavior; FlyBehavior flyBehavior; public void performQuack(){ quackBehavior.quack(); } public void setQuack(QuackBehavior quackBehavior){ this.quackBehavior = quackBehavior; } public void performFly(){ flyBehavior.fly(); } public void setFly(FlyBehavior flyBehavior){ this.flyBehavior = flyBehavior; } protected void swim(){ System.out.println("I can swim!"); } protected abstract void display(); }
分析:
在Duck.java 类这中,游泳行为swim()是鸭子实现类共有的特征且一定会游泳,因此,将其实现出来。而display()是所有鸭子的共有特征,但是不同鸭子的行为不一样,因此,将其抽象出来,所有继承该抽象方法的鸭子都要实现该方法。鸭子的飞行行为和叫的行为,并不是所有鸭子的共有特征,因此,将其声明为接口,这样,所有实现该抽象类的类可以按需要不要去关心鸭子的飞行和叫的行为,达到低耦合的目的。比如,此时,如果有些鸭子需要跳舞的行为,则可以同样添加一个跳舞的接口。
补充:
关于接口中的行为有两种:
一种是获取接口的行为,如:performFly();
另一种是改变接口的行为,如:setFly() (改变行为实现对鸭子的行为进行动态设置)。
FlyBehavior.java类:
public interface FlyBehavior { void fly(); }
两个实现FlyBehavior.java类如下:
Fly.java类:
public class Fly implements FlyBehavior { @Override public void fly() { System.out.println("I can fly!"); } }
NoFly.java 类:
public class NoFly implements FlyBehavior { @Override public void fly() { System.out.println("I can't fly!"); } }
QuackBehavior.java类:
public interface QuackBehavior { void quack(); }
两个实现QuackBehavior.java类如下:
Quack.java 类:
public class Quack implements QuackBehavior { @Override public void quack() { System.out.println("I can quack!"); } }
NoQuack.java 类:
public class NoQuack implements QuackBehavior { @Override public void quack() { System.out.println("I can't quack!"); } }
一个Duck.java的实现类如下:
MallardDuck.java 类:
public class MallardDuck extends Duck { public MallardDuck(){ quackBehavior = new Quack(); flyBehavior = new Fly(); } @Override protected void display() { System.out.println("I am green!"); } }
分析:
上述实现类对于Duck.java的实现类中,在构造函数中实例化鸭子的飞行行为和叫的行为。另外:对于鸭子的飞行行为和叫的行为可以在后期通过set函数进行更改。
实际调用的main方法如下:
public static void main(String[] args) { Duck mallard = new MallardDuck(); mallard.performFly(); mallard.setFly(new NoFly()); mallard.performFly(); }
输出:
I can fly!
I can't fly!
实现了运行时动态更改鸭子的飞行行为。
总结分析:
抽象类中的三种行为:
1、所有继承该抽象类都会有该行为,且行为都一样。(具体方法实现)
2、所有继承该抽象类都会有该行为,但行为都不一样。(抽象方法)
3、只有部分继承该抽象类会有该行为。(面向接口编程)
使用模式最好的方式是:“把模式装进脑子里,然后在你的设计和已有的应用中,寻找何处可以使用它们。”以往是代码复用,现在是经验复用。
OO原则:
1)封装变化(代码复用,低耦合)
2)多用组合,少用继承(推荐has a ,少用is a)
3)针对接口编程,不针对实现编程
相关文章推荐
- java 设计模式-行为模式之观察者模式
- java学习笔记(二十七)抽象类与设计模式
- 设计模式--行为模式--状态模式--Java
- 设计模式--行为模式--策略模式--Java
- Java设计模式(21)——行为模式之备忘录模式(Memento)
- java设计模式 -------- 行为模式 之 策略模式(2)
- Java设计模式_行为型_观察者模式_任意行为的监听
- Java设计模式(23)——行为模式之访问者模式(Visitor)
- JAVA中接口和抽象类的妙用-我自己也不知道这个是什么设计模式
- 设计模式--行为模式--Collecting Parameter--Java
- Java设计模式(19)——行为模式之责任链模式(chain of responsibilitiy)
- JAVA设计模式 —行为模式总结
- JAVA中几个易混淆关键词的理解:行为,隐藏,组合和继承,覆写和重载,多形(多态)性,动态绑定,上溯造型,抽象类,接口
- java设计模式 -------- 行为模式 之 策略模式(3)
- 【设计模式】深入理解Java的接口和抽象类
- Java设计模式(15)——行为模式之策略模式(Strategy)
- java行为设计模式——访问者模式
- java设计模式--基础思想总结--抽象类与架构设计思想
- Java中抽象类的实际应用:模板设计模式
- Java 设计模式之观察者模式的详解(行为模式)