两个例子:
例子1: 一个 ftp 下载器
例子2: 支付参数
总结:
1. 接口和实现. 父类和子类, 组合都能实现 抽象,层级.
2.要达到最好的泛化.最好是无参数,无返回值.所有都是变成 field.
3.组合的赋值是立体的.(一个嵌套一个的赋值,不可能是 abstract class), 继承的new 实例的赋值是拉平的.( 每一层都赋值,不过容易搞不清楚每一层需要赋值哪些参数.)
方法论:
1.思考每个层级需要哪些字段
1.1 这些字段是否可枚举化. (可枚举化的放 field,不可枚举化的放到接口里)
这样的好处是最下层的bean 都可以通过 spring 容器来管理. 父类的 bean 该 autowired 的也可以 autowired.
父类不能autowired
1.2 最终的 spring bean.
如无必要,勿增实体,延迟具体化.卡姆剃刀法则
成功的设计
配合 spring 的动态配置获取. 因为要根据可变参数具体化(实例),所以无法利用 spring 的配置了.
无法固定的东西通过参数传递. 但是一旦有了形参,通用性就降低了.
如果要更好的使用 spring 的容器,那么设计的时候就要明确可固化和不可固化参数.
例如:ftp 下载.前缀可固化. 文件名依赖 Date 可变.
概念线(继承) | 实例线(继承概念先,实例线垂直上是依赖) |
ftp 下载基本配置: host ,userName ftp 下载器: 1.下载地址,2.本地文件保存地址. 3.ftp 下载基本配置 渠道下载器 1.remotePrePath 2.localPrePath | phoenix 渠道下载器 继承 <渠道下载器>: 无自有属性. 把 userName 和远程remotePrePath初始化. |
业务下载器: 1.midPath (远程和本地保持一致) 2. 文件名(远程和本地保持一致) | phoenixPay 渠道下载器 ? |
设计的时候可以用字段, 如果该层级的具体化类能赋值的用 field.
如果具体化类不能赋值的最好用abstract getField()方法. 这样能避免继承者忘记掉赋值相关属性.
不过如果想用组合的方式,那么就无法用 abstract 了.
好的犯案. 通过初始化方法来初始化. | 通不好的方案,过类来初始化 |
不算成功的设计1:
ftp 下载基本配置: host ,userName
ftp 下载器: 1.下载地址,2.本地文件保存地址. 3.ftp 下载基本配置
渠道下载器 1.remotePrePath 2.localPrePath
业务下载器: 1.midPath (远程和本地保持一致) 2. 文件名(远程和本地保持一致)
具体化:
phoenix 渠道下载器 继承 <渠道下载器>: 无自有属性. 把 userName 和远程remotePrePath初始化.
phoenixPay 渠道下载器 ?
问题来了:
phoenixPay 渠道下载器 到底是继承 <phoenix 渠道下载器> 还是 <业务下载器>?
答: 如果具体化没有新增的字段,那么暂时先别具体化.把渠道和业务具体化放到一起.少一个类.
解决方案(解决双继承问题):
phoenix 渠道下载器 继承 业务下载器:
phoenixPay 渠道下载器 继承 phoenix 渠道下载器
支付参数的具体化却不同.
支付宝参数和微信参数不同.
都是渠道的具体化,各自支付宝和微信的biz 子类,都要各自演化. 无法有一个通用的 biz子 类.