设计模式_

0

评估代码质量:可维护性,可读性,可拓展性,灵活性,简洁性,可复用性,可测试性

1. 面向对象

抽象:接口interface,函数方法;作用屏蔽细节;
封装:作用隐藏信息,可控
继承:作用:复用
多态:继承并重写,interface,作用,提高代码复用性,设计模式实现的基础

破坏面向对象

  1. 所有属性都有get set,任意处都能调用修改破坏了一致性和封装
  2. constants类,被很多地方引用,打包引入不必要的(尽量放到constant依赖的类中,尽量细化,如redisconstant,dbconstant),utils类同理
  3. 基于贫血模型的开发方式

抽象类和接口(基于接口而非实现编程)

is-a和has-a的区别
抽象类:代码复用
接口:解耦(定义和实现分离)

基于接口而非实现编程

  1. 函数命名不能暴露实现细节
  2. 使用者依赖接口编程
  3. 接口通用,替换实现的时候,不需要1接口定义的改动

多用组合少用继承

继承层次高,可读性降低,父类抽象方法违背最小知识原则(AbatractBird fiy())
接口,组合和委托代替继承(flyable接口)
在这里插入图片描述结构稳定,继承关系简单,层次低适合用继承(模版模式)

mvc,充血,贫血,domain

do,vo和service分离,数据和业务隔离,贫血模型,破坏了封装性
充血模型的ddd也是按照mvc三层架构,区别在service层,
贫血(重service轻bo);适合简单的业务
充血(重domain轻service);适合复杂的业务
充血模型业务逻辑代码移到领域模型domain(充血的bo)中,能实现复用,service层跨领域模型调用,还有幂等,mq,log等,service依赖domain

面向对象开发

面向对象分析:输出需求描述,或者流程图时序图
面向对象设计:(需求转化为类的设计)
1. 识别哪些类(authToken,apiRequest,passwordStorage)
2. 定义类的属性方法
3. 定义类与类之间关系(泛化,实现,组合,依赖)
4. 类组装提供入口(auth函数)
面向对象实现:(编码)

2. 设计原则

SOLID原则

  1. S(single)单一原则:不同场景标准不一,可以通过方法是否过多,依赖的类过多,私有方法过多,难以命名;
  2. 开闭原则:对拓展开放,对修改关闭(新功能要拓展代码而不是修改代码);编码参考
    实践:多态,基于接口编程,依赖注入,设计模式
  3. 里氏替换:子类替换父类,不改变原有程序逻辑及正确性;拿父类的单元测试运行子类,结果要一致
  4. 接口隔离原则:不要暴露不必要的接口功能,类似单一原则
  5. 依赖反转原则(依赖倒置)
    控制反转:对流程的控制从程序员到代码框架;可以通过依赖注入,模版模式等
    依赖注入:不通过new的方式,而是传参,构造函数等,注入的对象可以是接口
    spring的控制反转就是通过依赖注入实现的
    依赖反转:高低层之间通过抽象(接口)来互相依赖,抽象不依赖细节,细节依赖抽象

KISS原则(keep it short and simple);可读性高,不要过度优化,用已有类库
DRY原则(donot repeat yourself);do,vo,bo重复,可以用继承来优化
迪米特原则:模块只应该了解与之关系密切模块的有限知识(有限的方法);有限知识可以通过实现多个接口来实现

方法技巧:画图,聚焦简单应用场景,然后迭代;画系统图;拆分;看26,39,40

3. 编程规约与代码重构

小重构
单元测试保证重构不出错
提高代码可测试性,mock数据,依赖外部的服务就mock解依赖

大重构
解耦,方法:封装抽象;中间层;模块化
在这里插入图片描述

编码技巧
1:不要用函数参数控制逻辑
在这里插入图片描述

2:使用解释形变量
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
看35

异常返回

能用异常尽量不用错误码;因为异常能携带更多信息
查找的函数不存在返回异常,null,-1都可以;但是要规范和说明清楚
返回空集合或者空字符串不用做判空逻辑
异常抛出,看外层是否关心,关心则抛出,否则吞掉

4. 设计模式

创建型:单例,工厂
结构型:代理,乔接,装饰者,适配器
行为型:观察者,模版,策略,责任链

1.创建型(创建和使用的解耦)

单例

作用1:解决并发冲突
2:代表全局唯一,配置类

private构造函数,创建对象要线程安全,getInstance性能要高,是否延迟加载

1:饿汉式,类加载的时候instance就已经创建并初始化,缺点不支持延迟加载,占用资源多
在这里插入图片描述

2:懒汉式,可延迟加载,缺点是getInstance方法需要加锁,并发度低
在这里插入图片描述
3:两阶段锁+volitile(禁止冲排序访问到并发中未初始化的对象)
4:静态内部类;外部类加载的时候不会创建内部类的实例对象,getInstance创建内部类
5:枚举;利用枚举本身的特性
在这里插入图片描述

单例是进程间唯一,线程间唯一可以用threadlocal

工厂

工厂方法,抽象工厂

简单工厂:通过if返回对应的多个对象
在这里插入图片描述

工厂方法:去调简单工厂的if(工厂的工厂)
在这里插入图片描述

构建者模式(Builder,使用)

建造者类负责对象的创建;可以定制化的创建对象
适合以下场景
在这里插入图片描述

原型模式(复制对象)

深浅拷贝

不可变模式

jdk 的Collections.unmodifiableList 引用
guava的ImmutableList.copyof 值,深拷贝

2.结构型(一层wrapper类封装原始类)

代理模式,装饰器,适配器可以统称为wrapper模式,可以通过组合,对原始类二次封装

代理模式(给原始类增加功能,使用)

功能:不改变原始类,通过代理类增加功能

实现方式
1: 代理类和原始类实现相同的接口,代理类中注入原始类,然后代理类添加增加的代码;通过接口创建代理类进行调用
2: 对于外部类,可以通过继承的方式
3: 动态代理,即运行时动态创建代理类; @Around注解

@Pointcut("execution(* com.controller.*.*(..))")
    public void pointCut2() {}

    @Around("pointCut2()")
    public Object run2(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取方法参数值数组
        Object[] args = joinPoint.getArgs();
        //得到其方法签名
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        //获取方法参数类型数组
        Class[] paramTypeArray = methodSignature.getParameterTypes();
        logger.info("请求参数为{}",args);
        //动态修改其参数
        //注意,如果调用joinPoint.proceed()方法,则修改的参数值不会生效,必须调用joinPoint.proceed(Object[] args)
        Object result = joinPoint.proceed(args);
        logger.info("响应结果为{}",result);
        //如果这里不返回result,则目标对象实际返回值会被置为null
        return result;
    }

桥接模式(try)

将抽象部分与实现部分分离,使它们都可以独立的变化。
抽象类依赖实现类,jdbc抽象代码依赖mysql实现
在这里插入图片描述

在这里插入图片描述

装饰器模式(原始类增强的功能,支持嵌套,使用)

场景:房子装修,画图,io类
shape类画图,抽象draw方法,但要有颜色,粗细等功能的话。都放在draw方法中不合适,此时装饰器嵌套
在这里插入图片描述
与代理区别:可以层层增加增强的功能。而代理模式则一般是用于增加特殊的功能
解决继承关系过于复杂的问题,给原始类增强的功能,在不想增加很多子类的情况下扩展类。

实现:
装饰器类继承父类;多个子类可以嵌套(类似代理模式的实现方式1),一层嵌套代表多一层功能,实现功能增强
Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。

适配器模式(兼容老接口,调用依赖的外部接口,implents ITarget,使用)

可以通过组合(内部依赖对象)或者继承的方式
如果adaptee和itarget很多一样的方法,推荐用继承,代码少一点
如果adaptee和itarget很多一样的方法,推荐组合,更灵活

门面模式

为子系统提供一个统一的接口,定义一组高层接口让子系统更易用
解决了易用性(屏蔽底层),高性能(减少调用),分布式事务问题(spring同一接口事物)

组合模式

将一组对象组合成树形结构
这种模式创建了一个包含自己对象组的类

享元模式(实现)

被共享的单元,享元对象需要是不可变对象
可以用工厂类+map存储不变对象

3. 行为型(行为的解耦)

观察者模式(EventBus,看源码,使用)

一对多的依赖,被依赖的发生改变,依赖对象做出响应
producer-consumer;subject-observer;dispatcher-listener;
一般的模版
在这里插入图片描述
在这里插入图片描述
上面是同步阻塞,还可以异步非阻塞(新线程),跨进程,跨应用(mq,rpc)

可以用google的guava EventBus

模版模式(复用,扩展,使用)

模版定义骨架,可以定义为final,某些实现延迟到子类实现,abstract
在这里插入图片描述

应用:
复用:java inputstream read(),abstractList add()。
扩展:servlet的父类的service方法是模版方法,会调用子类可以自己实现的doGet和doPost方法

和回调的区别(看)

策略模式(解耦策略的定义,创建和使用,避免if,else太多,使用)

定义一组方法,可以相互替换,比如通道的选择
定义通道接口并实现,工厂类创建通道,调用工厂类使用不同通道策略,需要传type

避免if,else;满足开闭原则,新增策略时,集中化改动代码,减少引入bug风险

责任链模式(写,前置处理,使用)

存在两种,一种截断式,另一种所有处理器都要处理
在这里插入图片描述
在这里插入图片描述
看servlet的实现63

状态模式(没看)

迭代器模式(类库已提供,看)

访问者模式(一般不用,难,没看)

备忘录模式(没看,用的不多)

主要用于防丢失,恢复

命令模式(不常用)

把函数封装成对象可以存储下来,主要适用于控制命令的执行,比如异步,延迟,排队执行命令(请求),存储命令(请求)
游戏的服务端,接收命令和处理逻辑

解释器模式(没看,很少用,规则引擎,编译器)

中介模式(少用)

类似代码的中间层,将多对多的网状关系转为一对多的形状关系
在这里插入图片描述
飞机和塔台沟通而不是其他飞机沟通,微服务的服务治理

经常看74的总结回顾

5. 实战

看77
大型项目开发经验linux:封装和抽象,分层模块化,基于接口通信,高内聚松耦合;为扩展设计(讲可变部分封装接口供外部使用,只改变实现);kiss原则
Guava

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值