简介
写了几年垃圾代码在设计模式上吃过亏,这次看到一篇文章,觉得讲的太好了,就和讲故事一样,逻辑思路很清晰,来来来 ,玩起来,躁动起来…
看着讲了组合和委托,之前对这个概念不太清晰,现在好好梳理一下,主要研究组合和委托解决的是什么问题
为什么少用继承?
假设: Anmial->鸟类->老鹰,大鹏,凤凰
常规认知的情况:鸟类都会飞,
所以class Bird extend Animal{ protected void fly() }
但有一个例外,鸵鸟也是鸟类,但它不会飞!
class Ostrich extends Bird
继承是实现多态的基础:
- Bird ostrichBird=new Ostrich()
鸵鸟即是鸟,又是鸵鸟。那么外部调用方就有可能调用 ostrichBird.fly()父类的方法,但是ostrichBird这个对象是不能飞的,这里逻辑就错误了
那怎么办?怎么解决逻辑错误?
方法一:重写方法,抛出异常
在Ostrich中重写fly()方法中抛出throw UnSupportedMethodException(“I can’t fly”); ostrichBird.fly();
public class Ostrich extends Bird{
@Override
public void fly(){
throw UnSupportedMethodException("I can't fly");
}
}
缺陷:
这样虽然能解决问题,但是增加了没有必要的代码,违背了最小知识的设计原则
什么是动态调用(多态)?
子类重写父类方法,多个子类继承了父类,父类引用了子类,父类调用被重写的方法时,就是分别动态调用的各个子类的方法
方法二:增加一层继承关系来区分
做区分:
再抽离一层public class FlyBird,public class UnFlyBird.
继承UnFlyBird,UnFlyBird没有fly()方法
这样虽然能解决问题
但假如有一种鸟类:天鹅,会游泳会飞,鸵鸟不能游泳不能飞
那么就会产生4种抽象类:
1.会游泳会飞,
2.不会游泳会飞,
3.会游泳不会飞,
4.不会游泳不会飞
那么这样继承的层次就太深了:
Animal->FlyBird,UnFlyBird->FlySwimmingBird,UnFlySwimmingBird,FlyUnSwimmingBird,UnFlyUnSwimmingBird
缺陷1:
层次太深,不方法维护和查看代码实现,树形结构,从Root到Item,越往下,层次越深
缺陷2:
父类和子类,强耦合,父类更改代码后,所有子类都会收到影响,比如子类方法中 super.fly()父类方法,父类方法改变
方法三:利用has-a Interface来解决这个问题
利用interface的思想:
把原来以继承方式组装的高层次的树形结构代码层次,转化为以接口这种可装载,可卸载的平层(只有一层) ,因为实现类只有两种情况(有该接口:无该接口)
虽然接口解决了:最小知识原则问题,以及强耦合从is-a转变为了has-a的关系
缺陷:
但接口只声明方法,不定义具体实现,所有会下蛋的鸟类都要实现eggLay()方法,而且eggLay()的逻辑都是一样,都是System.out.println(“会下蛋”);。这时就需要把这部分抽离出来,用一个公共的类来实现
//天鹅
class Swan implements Flyable, Swimmingable, EggLayable {
@Override
public void fly() {System.out.println("会飞");}
@Override
public void swimming() {System.out.println("会游泳");}
@Override
public void eggLay() {System.out.println("会下蛋");}
}
class Ostrich implements EggLayable { // 鸵鸟
@Override
public void eggLay() {System.out.println("会下蛋");}
}
interface Flyable { void fly();}
interface Swimmingable { void swimming();}
interface EggLayable { void eggLay();}
方法四:接口 组合 委托
组合思想:再加一层类(来把多个类相同功能的方法实现出来),然后在子类声明这个类。
委托思想:其实很容易理解,就是把大家都会干的事情"下蛋"这件事情,委托给公共类eggAbility来处理
组合和委托配合起来使用
public class ExtendInterface {
/**
* 让天鹅和鸵鸟下蛋 哈哈哈哈...
*/
public static void main(String[] args) {
EggLayable swanEggLay = new Swan();
swanEggLay.eggLay();
EggLayable ostrichEggLay = new Ostrich();
ostrichEggLay.eggLay();
}
}
// 天鹅
class Swan implements Flyable, Swimmingable, EggLayable {
Flyable flyAbility = new FlyAbility(); // 组合
Swimmingable swimmingAbility = new SwimmingAbility();// 组合
EggLayable eggAbility = new EggAbility();// 组合
public Swan(){System.out.println("我是天鹅");}
@Override //委托
public void fly() { flyAbility.fly();}
@Override //委托
public void swimming() { swimmingAbility.swimming();}
@Override //委托
public void eggLay() { eggAbility.eggLay();}
}
class Ostrich implements EggLayable { //鸵鸟
EggLayable eggAbility = new EggAbility();// 组合
public Ostrich(){ System.out.println("我是鸵鸟"); }
@Override
public void eggLay() {eggAbility.eggLay(); } //委托
}
// interface
interface Flyable { void fly();}
interface Swimmingable { void swimming();}
interface EggLayable { void eggLay();}
// 公共方法的实现类
class FlyAbility implements Flyable {
@Override
public void fly() {System.out.println("飞一会儿"); }
}
// 公共方法的实现类
class SwimmingAbility implements Swimmingable {
@Override
public void swimming() { System.out.println("游泳"); }
}
// 公共方法的实现类
class EggAbility implements EggLayable {
@Override
public void eggLay() {System.out.println("下一颗蛋"); }
}
总结
代码组织结构中经常会出现两类问题:代码层次过深问题,代码不能复用问题
Interface:解决代码层次问题
组合和委托:解决代码复用问题