写点什么

设计模式第三周总结「架构师训练营第 1 期」

用户头像
天天向善
关注
发布于: 2020 年 10 月 03 日

 

设计原则比较抽像,设计模式则比较细化,让人可以照着模板套用,当然这些模式有些比较常用,有些也比较难理解。

 

面向对象需要以管理者的视角,这件事需要哪些人完成,这些人的职责是什么,怎么分工协作的。设计模式一般都是为了解藕,划分角色,理清职责,按需增加中间类或是上下文类,类与类之间可能是依赖,关联,聚合,组合关系。控制代码的复杂度,减少代码复杂度,新增功能最好是增加类(开闭原则),修改代码时最小化,集中化(复用后可以集中化,有中间层也集中化,划分清楚角色也集中化)。写代码,你需要以需要哪些类一起完成业务功能,如果功能简单并且较稳定,两行代码就完成了,就不用过多考虑了。

 

不需要太纠结与标准的UML模式图不一样,你可以理解为有标准的实现,有变种的实现或是叫做被本土化了。一切都是为了解决问题出发,对于不常用,也难理解的可以暂时不做过多关注。

 

写代码要想着复用,想着扩展点,抽公共方法,变成类,变成接口或是抽像类,一般可以分为定义算法,在哪里创建,客户端怎么使用,其中算法中包含接口与抽像类,他们是怎么组织在一起的,他们之间是怎么交互的,怎么形成一个整体对外提供方法。

可以把设计模式给放大一下思考,把它认为是一个组件或是一个模块,或是一个C/S架构的系统。

常用java或框架使用什么设计模式

Java

工厂模式calendar中不同时区判断的初始化,Integer.valueOf方法

模板模式Servlet模板中service方法,doPost doGet自已重写

装饰器模式inputstream fileInputStream,FileInputReader

动态代理Proxy.newInstace,InvokeHandler接口

享元模式Integer,Long -128到127数值时会存到缓存中

迭代器模式List Iterator迭代器

 

Spring

代理模式,spring aop,实现事务功能

单例,controller,service,dao都是单例

模板方法,jdbcTemplate,restTemplate

jdbcTemplate的模板方法并不体现在有抽像类,还是体现在回调方法

Execute(sql)里面从DataSourceUtils中获取连接,取出statement,执行statementCallback方法中的doInStatement(statement stmt),将stmt.execute(sql)方法给独立出来,可能需要扩展

工厂模式,BeanFactory

观察者模式,事件驱动,aplicationContext中的事件

适配器模式,spring mvc的视图输出json,string,xml等用了适配器

委派模式,dispatchServlet

 

Mybatis

工厂模式sqlSessionFactory

模板模式BaseExecutor sql执行逻辑

建造者模式sqlSessionFactoryBuilder

单例模式ErrorContext线程级别

适配器模式日志处理,可以使用log4j log4j2 commonlog

代理模式mapperProxyFactory

装饰器模式缓存基本存储,还有先进先出,最近最少使用,同步缓存

 

Netty

单例模式ReadTimeoutException与MqttEncoder饿汉模式

模板模式abstractBoostrap与它的子类serverBootstrap bootstrap

责任链模式pipeline

构建者模式serverBootstrap bootstrap的实例化

 

什么时候用设计模式

写web业务开发的人员,更多的在业务层面,controller,service ,dao,然后是一些工具方法,使用消息中间件或是缓存,我们创建对象new Object(),或是仅几个入参,构造函数一般不处理业务,我们印象中经常写的是PO,VO类,业务中也多使用if else或是switch判断业务。

 

你写的类中,如果业务复杂,代码量比较大,但是没有用到接口与抽像,那扩展性与复用性就不太好。

 

写业务功能时,可以使用设计模式,例如不同会员的折扣,不同活动中商品的优惠,支付方式等,消除if else与switch语句等。

 

写非具体业务功能场景,例如写应用中间件(tomcat,mq,cache,oss对象文件存储),写基础框架(http调用框架feign,rpc框架dubbo,网络通信netty, ioc容器,spring mvc,mybatis,hibernate,sharding jdbc),写服务治理中间件(注册中心eureka,网关zuul,限流熔断hytrixs,监控或度量promethus,分布式事务seata, 调用链路zipkin)

 

比较精通设计模式的人,在需求与扩展都思考过后,进行模式设计,比较符合先设计与开发的思想,这样正常来说比较节约时间

系统需要重构了,进入重构代码阶段,考虑职责,复用,类怎么组织与扩展

新手可以编写完成代码,再思考代码调整,让代码易读,减少重复,可扩展

 

设计模式分类

GOF设计模式23种可以分类为创建型,结构型,行为型

l 创建型

工厂模式可以分为三种,简单工厂,标准工厂模式,抽像工厂模式

分离对象的创建与使用,类的创建为单独一个类,对于不复杂的对象创建没有必要使用工厂模式

 

简单工厂

不在GOF设计模式中,但开发过程中比较常用

简单工厂又叫静态工厂

单独一个类负责对象的创建,这个方法经常根据入参,进行if else的判断,可以使用map缓存起来,或是使用配置文件配置,结合反射来实现

当然如果创建的对象的逻辑比较简单,判断比较少,也没有必要解决if else的问题

标准工厂模式

将单独一个类的工厂,变成接口与多个工厂实现类,在使用时,进行if else判断,好处是扩展方便,在使用端一样违背开闭原则

当然使用端可以使用Map方式缓存,即查表或字典表消除if else

 

抽像工厂模式

工厂接口定义是目标的单一分类,如果出现二种分类方式,则用标准工厂模式不好解决,在工厂模式的基础,工厂接口类中的一个接口声明变成多个接口,即多种分类维度,一个维度一个接口,比较少用,不需要过多关注

 

单例模式

饿汉式

懒汉式

懒汉式对于锁的粒度的控制可以考虑双重检查

静态内部类

枚举方式

 

构建者模式

工厂模式是创建符合业务需要的对象,构建者模式考虑一个对象的定制化创建。

通过方法名的方式更清楚需要设置哪些参数,必填的参数放到构造方法中,最终创建对象通过build方法,对于一些参数的校验,或是参数之间有依赖关系校验都可以放到build方法中,例如大小参数合法设置比较,例如一个设置了true,另外一个则不能设置为true。表现为链式调用,另外初始化后,可以让某些属性不能再进行set设置,则相应set属性方法不需要暴露。

 

原型模式

二进制数据复制,不需要从头开始初始化对象,初始化对象有什么步骤?

对象的深与浅克隆,对于类中的有引用对象,则面要在clone方法中重新赋值,否则克隆出来的新旧对象实例还是使用同一个引用对象

 

l 结构型

类对象组织方式,组装,或组合关系。这里的组合关系,并不是组合模式。

 

装饰模式

有相同接口或抽像类,增强功能

 

代理模式

增加一些非核心业务功能,或是叫附加功能,与业务核心功能解藕,例如分库分表路由,监控,统计,鉴权,事务,日志,缓存等

静态代理与动态代理,静态则手工为需要代理的类新建一个对应的代理类,动态代理则是动态自动创建代理类,使用jdk提供的动态代理 自定义proxyFactory代理工厂生成类中获取代理实例方法中使用Proxy.newProxyInstance,关注第三个参数实现InvokeHandler接口 或是第三方的cglib,字节码增加,子类代理,自定义proxyFactory代理工厂类实现MethodIntercer,获取代理实例方法中使用Enhancer,设置父类,设置回调本身代理工厂类中的interceptor方法。

Spring aop面向切面的原理,也是为了与核心业务解藕,使用也是动态代理模式

 

门面模式

聚合层,对外提供一个接口,这个接口调用多个子接口

 

适配器模式

转换接口功能,让功能符合要求,例如手机电源适配器,220V的电压变成5V

 

桥接模式

不常用 



组合模式

处理树形结构的数据,父子结构,组织数据时,使用递归方式,例如awt中的视图窗口元素的组织,文件管理,目录下有子目录与文件,需要计算目录与文件个数

 

享元模式

创建对象实例,先判断缓存中是否存在,没有创建后会放进缓存中

 

l 行为型

类或对象交互,有交互则一定有不同角色,例如发送者与接收者,发布者与订阅者,分发者与监听者,事件发射者与事件监听者等

 

模板模式

定义一系列算法,有的实现,有的推迟到子类实现

 

状态模式

状态机由有状态,事件,动作三部分组成

事件触发状态转移与动作执行,当然动作不是必要条件

 

策略模式

控制策略算法的复杂度,需要一个上文类或是中间类决定使用哪个策略算法。这个中间类可以是工厂模式实现,也可以是简单的关联。

由算法定义,创建,使用三部分组成

算法定义:声明接口类与不同的实现算法

创建:需要区分策略算法是法有状态,如果有则是策略算法类中有成员变量,则不能放到map中缓存,传入参数,经过if else比较,或是通过map查表法消除if else

使用:非运行时静态使用策略,策略算法选则是固定的,则是基于接口编程或是体现面向对象多态性。运行时动态确认策略算法,可能是因为配置文件(配置文件修改后可以动态加载,不需要修改代码也可以确认不同策略算法),系统环境变量,一些计算判断条件。

场景:1不同会员购买商品不同优惠2工作流引擎,节点的流转3对不同大小数据集进行排序,快排,归并,堆排序等4不同的订单类型,普通,团购,秒杀,促销订单等,不同的业务逻辑

 

职责链模式

一个请求需要依次经过多个处理器处理,可以某个处理器处理完后不再往后传递,也可以所有的处理器都处理一遍

 

备忘录模式

记录历史对象实例,上一步,下一步,数据版本控制

 

命令模式

比较不常用

将函数封装成为对象,目的是将函数做为参数传递给其它函数

 

中介模式

不常用

观察者模式解藕参与者,并且是单向的

访问者解决对象与对象多对多的关系,关系变更为星形,多对一,参与者的身份可以是多个,既是发送者,也是接收者

 

观察者模式

角色有观察者与被观察者,这两个词比较绕,可以用主题与订阅者这两个角色比较好理解

主题的职责:添加删除订阅者(有订阅者清单),通知所有订阅者

订阅者的职责:接收消息通知

当然可以认为引入了一个mq的消息中间件,发布订阅的模式,一个系统发布一条消息后,有不同的子系统根据这条消息处理自已的业务

与生产者消费者的区别,生产者与消费者更关注数据内容本身,主题订阅更关注通知订阅者了。

 

迭代器模式

解藕容器数据结构的基本操作与遍历操作

 

解释器模式

不常用

 

访问者模式

不常用

性能有关的设计模式

单例模式。对象的实例化是比较大的开销的

原型模式。通过在内存中二进制拷贝,可以节约一个新的实例化的时间

享元模式。缓存对象,String,Integer,Long(小于-127至128数字时缓存),mybatis,连接池中key对象管理

 

消除if else if else的方式

第一种为判断条件为字符串等固定值

1策略模式+工厂模式,将使用端的if else转移到了工厂类中

2按需使用map缓存实例化策略算法对象

3如果不能缓存,可以使用map缓存class类,然后通过反射每次调用实例化

第二种为判断条件为比较大小有范围等其它条件判断方式

1将比较方式为再抽像一层单独一个范围控制类,这个类定义比较方法与使用哪个策略

2使用List存储这个新抽像的范围控制类

3比较时遍历所有,判断符合条件调用具体算法,这样只有一层if else

 

当然可以不需要再抽像一层,策略算法中定义使用范围的方法,这样灵活度稍微低了一点

第三种为使用状态模式

 

第四种为使用职责链模式

 

不修改代码,已有系统可以识别新算法的方式

1注解,在新增加的类上加注解,使用相同注解类的地方则可以识别出来

2使用配置文件配置

微内核则是这样用的,dubbo新增算法和使用哪个实现类是使用注解与spi机制

 

发布于: 2020 年 10 月 03 日阅读数: 54
用户头像

天天向善

关注

还未添加个人签名 2018.04.27 加入

还未添加个人简介

评论

发布
暂无评论
设计模式第三周总结「架构师训练营第 1 期」