1.反射
数据驱动的好帮手
反射是将代码数据化
Class<?> personClass = Class.forName( "Person");
Person person= personClass.new Instance();
当你通过反射创建类时,你是把这个类名数据化了 ; 当你通过反射调用函数时,你把这个函数名数据化了 ; 当你通过反射访问成员变量时,你把这个成员变量名数据化了
反射能将模块和模块之间的绑定从编译期延迟到运行期
反射的缺点
缺点一: 破坏封装
缺点二 :影响阅读和调试 阅读时,你没有办法直接进入到相应的代码定义,也没有办法通过引用查找
2.继承
里氏替换原则
两个有代表性的违反里氏替换原则的场景:
1)驼鸟非鸟:所有鸟类统一有一个Fly抽象方法,驼鸟Ostrich也继承于鸟,所以通过继承也自带了Fly方法可驼鸟那么重,根本不会飞怎么办呢? 要不让它假装能飞吧,在 Fly 里面什么都不做 : 然而有一天露馅了,驼鸟被加入 了一个游戏场景 ,猎人开枪打飞出来的鸟。 轮到调用驼鸟时猎人等了很久,屏幕却是空的
两种解决方法
方法一: 将Fly抽象成一个接口,从Bird基类剥离出去
方法二:创建一个“会飞的鸟” FlyBird的中间类,并继承自 Bird类
如果抽象出的方法不依赖于新增数据,就剥离出新接口; 如果抽象出的方法需要新定义数据,就新定义中间类
2)不听老人言
指的是子类扩大了父类原有的行为,语法上是允许你随意复写,但业务上,只能有限制地复写。
学生 Student 类有个GetExamScore 函数,用来得到这次考试的分数,满分 100 。而老师 Teacher 类有个 GetScoreLevel(int score )函数,它根据学生的考试分数,给 他评个 “A” “B” “C”等级 。
现在有个高中生子类 SeniorStude时, 他们的考试满分是 150分,不是100分了。这会造成Teacher类GetScoreLevel函数统计失误, 发现A和B等级的比例大幅增加。
3.什么场景下用继承? 什么场景下用组合
1)多个子类出现后, 通过继承和多态从而产生动态的效果,这是组合做不到的
2)组合的优势在于,能够实现一个并不固定某具体功能的类
4.策略模式
如果有N个对象需要执行同一个方法,每个对象的方法内容不一样:
策略模式就会有一个专门负责计算的类族, 很多子类实现了这个接口
运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,但可以动态地在不同的策略实现中切换
如果使用继承,我们就需要定义N个子类。外层使用时,不用动态设置算法,但要创建 3个 Employee 子对象
可能会有疑问:到目前为止,组合和继承这两种方法似乎相差不大。 如果使用继承,那么为了区别工资的算法,需要定义3个子类 。 但使用组合,也有 3个策略类啊 。 至少,它们 的类数量是一样的 !
关键点 : 此时又来了一个计算假期的方法需求 。 根据每个人是否已婚、工作年限的不同等,又是一套独立的算法,这套算法也有 3种。此时业务上允许两套算 法两两组合,产生多种不同的变化。
用组合则有 3+3=6种子类,算的是加法,比较得体地应付了这种变化。 此时还用继承实现, 则需要定义 3×3=9种子类
5.依赖
在代码中的结构很简单,就是 B 类作为 A 类某种函数的一个参数
组合和依赖的核心区别是 A 是否拥有 B 的一个对象实例,组合有,依赖则没有。 是否拥有 这个实例对象所产生的影响是深远的 。 因为组合里的这个对象是可以持久的,井且是状态相关的 。
以下情况是组合能做到而依赖做不到的:
组合里, A可以先初始化B 的实例,却并不急于马上调用B,我可以等到合适的时候再调用 。 这点依赖做不到,侬赖必须在该函数执行 期内去使用,否则对象被销毁,便过期了!
数据驱动的好帮手
反射是将代码数据化
Class<?> personClass = Class.forName( "Person");
Person person= personClass.new Instance();
当你通过反射创建类时,你是把这个类名数据化了 ; 当你通过反射调用函数时,你把这个函数名数据化了 ; 当你通过反射访问成员变量时,你把这个成员变量名数据化了
反射能将模块和模块之间的绑定从编译期延迟到运行期
反射的缺点
缺点一: 破坏封装
缺点二 :影响阅读和调试 阅读时,你没有办法直接进入到相应的代码定义,也没有办法通过引用查找
2.继承
里氏替换原则
两个有代表性的违反里氏替换原则的场景:
1)驼鸟非鸟:所有鸟类统一有一个Fly抽象方法,驼鸟Ostrich也继承于鸟,所以通过继承也自带了Fly方法可驼鸟那么重,根本不会飞怎么办呢? 要不让它假装能飞吧,在 Fly 里面什么都不做 : 然而有一天露馅了,驼鸟被加入 了一个游戏场景 ,猎人开枪打飞出来的鸟。 轮到调用驼鸟时猎人等了很久,屏幕却是空的
两种解决方法
方法一: 将Fly抽象成一个接口,从Bird基类剥离出去
方法二:创建一个“会飞的鸟” FlyBird的中间类,并继承自 Bird类
如果抽象出的方法不依赖于新增数据,就剥离出新接口; 如果抽象出的方法需要新定义数据,就新定义中间类
2)不听老人言
指的是子类扩大了父类原有的行为,语法上是允许你随意复写,但业务上,只能有限制地复写。
学生 Student 类有个GetExamScore 函数,用来得到这次考试的分数,满分 100 。而老师 Teacher 类有个 GetScoreLevel(int score )函数,它根据学生的考试分数,给 他评个 “A” “B” “C”等级 。
现在有个高中生子类 SeniorStude时, 他们的考试满分是 150分,不是100分了。这会造成Teacher类GetScoreLevel函数统计失误, 发现A和B等级的比例大幅增加。
3.什么场景下用继承? 什么场景下用组合
1)多个子类出现后, 通过继承和多态从而产生动态的效果,这是组合做不到的
2)组合的优势在于,能够实现一个并不固定某具体功能的类
4.策略模式
如果有N个对象需要执行同一个方法,每个对象的方法内容不一样:
策略模式就会有一个专门负责计算的类族, 很多子类实现了这个接口
运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,但可以动态地在不同的策略实现中切换
如果使用继承,我们就需要定义N个子类。外层使用时,不用动态设置算法,但要创建 3个 Employee 子对象
可能会有疑问:到目前为止,组合和继承这两种方法似乎相差不大。 如果使用继承,那么为了区别工资的算法,需要定义3个子类 。 但使用组合,也有 3个策略类啊 。 至少,它们 的类数量是一样的 !
关键点 : 此时又来了一个计算假期的方法需求 。 根据每个人是否已婚、工作年限的不同等,又是一套独立的算法,这套算法也有 3种。此时业务上允许两套算 法两两组合,产生多种不同的变化。
用组合则有 3+3=6种子类,算的是加法,比较得体地应付了这种变化。 此时还用继承实现, 则需要定义 3×3=9种子类
5.依赖
在代码中的结构很简单,就是 B 类作为 A 类某种函数的一个参数
组合和依赖的核心区别是 A 是否拥有 B 的一个对象实例,组合有,依赖则没有。 是否拥有 这个实例对象所产生的影响是深远的 。 因为组合里的这个对象是可以持久的,井且是状态相关的 。
以下情况是组合能做到而依赖做不到的:
组合里, A可以先初始化B 的实例,却并不急于马上调用B,我可以等到合适的时候再调用 。 这点依赖做不到,侬赖必须在该函数执行 期内去使用,否则对象被销毁,便过期了!