############### 先弄清楚类模型的关系 ############### 万物的抽象关系 ############### 1.组合 composition 实菱形 实线 无填充箭头 整体与部分的关系 同生共死 代码体现:成员变量 如:生命体与器官,http请求(请求行,请求头,请求体),教室(黑板、桌椅等),班级(学生、老师等) 2.聚合 aggregation 空菱形 实线 无填充箭头 整体与部分关系 可独立存货 代码体现:成员变量 比组合的关系弱 如:手机与手机零件(比如摄像头) 3.关联 association 实线 无填充箭头 是一种个体与个体关系,也可以是一种拥有关系(弱关系),可以是单向也可以是双向,还可以是自关联 代码体现:成员变量 如:老师与学生,学生与课程,夫妻,单身汉 4.泛化 generalization 实线 空心箭头 是一种继承、抽象关系 代码体现:继承 如:动物分为很多种,手机可分为很多种 5.实现 realization 虚线 空心箭头 是一种抽象到具体的关系,类与接口的关系 代码体现:impl 如:人会说话、猫会叫 6.依赖 dependency 虚线 无填充箭头 是一种使用关系 代码体现:局部变量,方法调用 如:人需要呼吸那就依赖于空气,人需要喝水那就依赖于水 ###############六大设计原则############### 1.开闭原则 对扩展开发 对修改关闭 用抽象构建框架 用实现扩展细节 2.依赖倒置 高层模块不应该依赖底层模块,他们应该依赖其抽象 3.单一职责 不要存在多于一个导致类变更的原因,一个接口/类应当只负责一项职责 4.接口隔离 不要用一个总接口,用多个接口进行功能隔离 5.迪米特法则 最少知道原则,既一个对象应当对其他对象尽量少的知道,降低耦合 6.里氏替换 一个引用了基类的地方都必须能透明化的替换成它的子类 ####################################### 强弱关系 泛化=实现 > 组合 > 聚合 > 关联 > 依赖 ############结构模式############## 1.适配器模式 将接口的功能转换成另一种接口表示,在不改变原接口的前提下,扩充了能力以及兼容性 比如:一个上层业务已经存在一个接口,但是另一个业务需要改动,为了不改变原接口的功能,用适配器模式可以做到兼容。 目的是为了改变接口功能 2.装饰器模式 动态的将功能附加到对象上,它比继承更有弹性,同种类型的单方功能组合和扩充(增强) 区分装饰者(附加)和被装饰者(原始),他们都有一个共同的超类 目的是为了单方面的增强功能 3.代理模式 有些服务不能直接访问,或者有安全控制,为了解决这个问题,使用代理模式。他解决的是控制问题, 4.外观模式 隐藏系统的复杂度,向客户端提供一个可以访问的接口 门面角色 子系统角色 客户角色 从规约上讲,系统方法应当是功能单一的,而使用单一功能方法组合的时候是复杂的,那么久需要一个统一的入口来组合这个复杂的过程,这个接口(方法)就是外观模式的体现 5.桥接模式 将抽象部分和它的实现分离,使他们能够独立变化,重点在于分离与独立变化 类爆炸,如不同的实现都得创建类,那我们能不能将实现分离,手机样式有很多种,不能因为样式变化我们就要创建一个手机类,手机类是固定的,但是它锁含的样式是可以变化的,由原来的样式-手机的关系转变为 手机-样式的关系 手机抽象 样式抽象 手机抽象包含样式的抽象 各自实现 手机实现加入样式的实现 取代多层继承 6.组合模式 部分整体模式,将对象组合成树形结构,使得用户对单个对象和组合对象具有一致性的访问性,并且可以适应通用类型的一并管理 核心是层级,相同的父类 举例: 文件夹和文件继承同一个父类 他们有共同的访问方法 7.享元模式 通过共享的方式高效的支持更多细粒度的对象 当存在大量对象的时候,可能会内存溢出,我们把其中公共的部分抽取,如果有相同的业务请求,直接返回在内存中已有的对象,避免重复创建对象。 说白了就是抽取对象的共性,由工厂创建成一个公共对象,并且将这些公共对象放入内存(全局map),当需要对象的时候根据唯一值到这个map中获取,注意一个问题,公共对象也需要释放(淘汰机制),否则会溢出。 ############################### ##########关系、行为模式############## 1.父类与子类关系 1.策略模式 将一系列的算法封装,而这些封装算法可以随环境、业务随意替代切换,并且他们的变化不会给客户端带来影响,前提是他们实现的是相同的接口 减少代码中的if。。。else。。。 也许在选择某个实现的时候还是需要if else的 但是对于客户端而言是不需要去关注if else 这部分业务的 2.模板方法模式 (抽象类)定义一系列的算法骨架,也就是实现的流程但不具体的实现,将实现延迟到实现类中 说白了就是先定义做一家事情的流程(抽象方法的顺序执行),但是不详细说明做的详情,抽象方法的实现由子类自己决定 比如:父类定义做饭(洗菜 切菜 炒 装盘),做饭的流程是预先定义好的,但是洗菜,切菜等的具体方式是需要根据做什么饭才能决定的 当做汤时,我们需要洗什么 切什么 有做汤的实现类决定 西红柿炒鸡蛋 切什么 洗什么 这个是由西红柿炒鸡蛋这个实现类决定的。 2.两个类之间 1.观察者模式 定义的对象间存在一种一队多的关系,当一个对象的状态发生变化的时候,其他依赖它对象都要得到通知,并被自动更新 一般适用于通知 2.迭代子模式 理解我们常用的Iteretor,一般由一个迭代器接口规定其操作(如:hasnext,next,remove等),然后由具体子类来实现。 通常用于顺序访问聚合对象的内部的各个对象而不需要暴露其内部表示(这个聚合对象的内部结构) 内部结构指:聚合对象的内部组成如:list、数组等结构,本来我们取聚合对象的时候是取其属性,然后按数据类型来获取这个属性包含的各个对象(迭代) 迭代子模式可以不需要暴露这个聚合对象的内部结构(被next、hasnext等方法屏蔽) 3.责任链 以链式处理方式来处理一组或多组不同类型的数据 1.多个对象协同处理数据,具体哪个对象能处理数据由由这些对象本身的业务划分(专属领域)来区分 2.可动态的指定一组对象处理,或动态的添加处理对象(设置下一个处理对象)。 3.在不明确处理者的时候,向多个处理者中的一个提交请求:就是不确定哪个对象能处理,被迫向链式处理结构提交数据,最终由能处理的哪个对象处理,这种情况不常见 4.命令模式 在一组操作中抽象出操作为命令(比如开、关、重启、注销等一组命令),由角色来区分职责(调用->接受->具体命令->执行者),他实现的是行为请求者与行为实现者的解耦,而这个解耦的关键是命令接受者 命令接受者作为中介,接受命令的同时又可以调用具体命令执行 抽象角色 命令调用者 命令管理者 命令抽象 具体命令 命令执行者 命令管理者包含抽象命令(具体命令),管理者执行的时候不用管具体命令是啥,只管执行, 具体命令包含命令执行者 这样在命令发生变化的时候,调用者不需要作出改变,而只要命令执行者或者具体命令去更改 有新增的命令只要扩充具体命令和执行者就行 3.类的状态 1.备忘录模式 又叫做快照模式,和日常中的存档类似,在不破坏对象封装性的前提下,捕获对象的内部状态,并在该对象之外保存状态,以便在以后能进行使用、恢复等 常见的就是日志备份,undolog,回退等等 发起人:提供创建备忘录和恢复数据的功能,实现其他业务,可以访问备忘录的实际内容 备忘录:存储备忘录 管理者:对备忘录进行管理,但不能访问备忘录的内容 2.状态模式 对象能够根据其状态自动的改变其行为,允许对象状态改变时改变它的行为 如视频播放,播放、暂停、快进、快退等的状态切换 暂停不能快进 state 抽象状态 concretestate 实际状态 context 环境角色 他包含了state 4.通过中间类 1.访问者模式 将作用于某种数据结构中的各个元素的操作分离出来封装成独立的对象,使得其在不改变数据结构的前提下可以添加作用于这些元素新的操作,为数据结构中的每个元素提供更多的访问方式 元素和元素的操作分开 抽象访问者 访问者抽象 具体访问者 提供对元素的扩充访问方法 抽象元素 结构中的元素 具体元素 具体元素 针对性的方法 对象结构 对象的聚合类型 对象结构传入visitor,元素接受访问者,元素调用访问者方法,访问者方法扩充对当前元素的操作方法 2.中介者模式 定义一个对象用于协调封装一系列对象的操作,而这些对象之间没有耦合关系,这些耦合关系被中介者处理。这个模式是迪米特法则(最少知道)的典型应用 比较好理解,就是中介把对象间要关联的操作和给做了 3.解释器模式 就是解释某些内容的含义,比如sql解释器,比较接近于底层,用的比较少 context 上下文 存入被解释的对象 解释的规则 创建一个非终结符的解释器 抽象解释器 解释器的抽象父类 非终结符解释器 中间解释器 可以有一个或多个 他可包含终结符解释器 一种类型的解释一般只与一种非终结符解释器对应 但一种类型的非终结符解释器 可以包含多个终结符解释器 这和组合模式有点类似 终结符解释器 最终解释器 发生真正的解释 不包含有其他解释器 一般一种规则对应一种终结符解释器 一般流程:创建上下文(填入共享数据和非终结符解释器 如:被解释对象,解释的规则等)->创建非终结符解释器(构建这类的数据解释所需要的的终结符解释)-> 调用非终结符解释器的解释方法->按规则调用终结符解释器的解释方法->终结符解释器按规则解释->返回结果