Java设计模式【总结版 -- 未完】

七大设计原则

一、单一职责原则

各司其职

降低类的复杂性
提高可读性

1、类级别:一个类只负责它自己的事

2、方法级别:一个类中每个方法只负责它自己的事

二、接口隔离原则

根据实现类被依赖调用的情况,将一个类中的多个方法,拆分到多个接口中。

不需要实现的方法,是可以拆分的。

三、依赖倒装原则

面向对象、面向接口

依赖于抽象,而不是具体的实现
尽可能地调用接口方法,而不是具体的实现类,接口设计相对于稳定,且可拓展。

四、里氏替换原则

子类尽量不重写父类方法

若子类重写父类方法特别多
可以将两个类放在同一级别,继承于同一个类
不将二者看为继承关系,而是组合关系
降低耦合性

五、开闭原则

对拓展开放、对修改关闭

要增加一个功能,要通过拓展而不是修改代码

六、迪米特法则

内部依赖的类不要对外暴露逻辑

七、合成复合原则

要使用别的类的方法,尽量使用依赖、聚合等方式调用,而不是继承它。

设计模式

一、单例模式

1、饿汉式(静态变量)

内部定义静态变量,初始化直接new一个
对外暴露获取的方法

缺点:
类装载时执行,可能造成懒加载无效,内存浪费

2、饿汉式(静态代码块)

设置静态代码块

3、懒汉式(线程不安全)

需要的时候,判断是否有实例,再去创建实例
多线程不安全

4、懒汉式(线程安全 – 同步方法)

获取实例的方法上加synchronized ,防止多个线程进入判断内部

5、懒汉式( 并不安全 – 同步代码块)

在get方法内,在创建时给创建的语句代码块加锁
多线程并不安全
依旧会使多个线程进入判断内部产生多个实例

6、双重检查

volatile 加在内部静态变量上,保证可见性
判断对象存在、加锁同步代码块、内部再进行对象=null 的判断

7、静态内部类

设置一个静态内部类X,X内部设置了直接new的静态变量对象。
静态内部类只有第一次加载类时初始化,JVM保证线程安全

8、枚举

设为枚举类

enum Singleton{
    INSTANCE;
}

不仅方法能正常使用,还能保证线程安全和单例,防止反序列化。

二、工厂模式

1、简单工厂模式

工厂类

  • 工厂类: 模式核心,创建产品
  • 抽象产品:具体的几种产品的抽象类父类或接口
  • 具体产品:工厂类生产的实例

建立一个工厂类,想获取什么样的实例对象,告诉工厂
由唯一的一个工厂类去创建各种实例

缺点: 新增一种,都要修改工厂中的方法

静态工厂模式:将生产产品的方法设为静态

2、工厂方法模式

多个工厂类+工厂接口(抽象类)

  • 抽象工厂 AbstractFactory: 具体工厂必须实现的接口或者必须继承的父类(抽象类)

  • 具体工厂 Factory:生产具体产品的对应工厂类

  • 抽象产品 AbstractProduct:具体产品必须实现的接口或者必须继承的父类(抽象类)

  • 具体产品 Product:具体工厂生产的实例

由于种类的复杂性
根据不同种类,创建不同的工厂

饮品有:牛奶工厂、茶叶工厂、果汁工厂……

各种工厂都实现同一个工厂接口,由工厂接口规定基本的方法。

缺点: 每增加一个类就要增加一个对应的具体工厂类

3、抽象工厂模式

多个工厂类+工厂接口(抽象类)
每个产品类使用多个不同的工厂实例

  • 抽象工厂 AbstractFactory:具体工厂类必须实现的接口或者必须继承的父类(抽象类)

  • 具体工厂 ConcreteFactory:生产不同产品族

  • 抽象产品 AbstractProduct:一个产品家族,每一个具体工厂都能够生产一整组产品。

  • 具体产品 Product:由相同或不同产品组的实例组成

由于产品生产复杂性
方法不一样,需要定义产品族,也就是将产品分类

比如:

小明家(工厂接口):土豆地(工厂)、白菜地(工厂)、猪圈(工厂)……
小红家(工厂接口):土豆地(工厂)、白菜地(工厂)、猪圈(工厂)……

土豆回锅肉 = 猪肉(小明家的猪)+ 土豆(小红家的土豆)

醋溜土豆丝 = 土豆(小明家的土豆)
……

每个工厂提供不同类别的具体实例
每个产品,内部定义它自己所需要的工厂,需要怎样的实例。

工厂方法模式和抽象工厂模式的区别:

  1. 工厂方法模式中一个工厂只能生产一种实例,而抽象工厂模式能生产多种实例
  2. 工厂方法模式中每个工厂生产出的实例就是一个单独的产品,而抽象工厂模式中虽然每个工厂创建的实例也属于一种产品,但重点解决的是由不同工厂生产的实例组合起来的复杂产品。

三、原型模式

实现 Cloneable 接口
重写clone()方法

获取复制体时,只要调用clone方法 完成对类及其属性的复制

浅拷贝:
clone提供的拷贝只针对基本数据类型
类的对象属性、集合属性等,并没有另外开辟空间
仍旧指向原来的属性地址

深拷贝:
集合类需要重写clone,集合类也能直接使用clone,都实现了 Cloneable

完全实现深拷贝
重写clone:对所有引用类型都需要clone,很麻烦。
实现序列化:以流的方式写入,再以流读出,返回一个新的对象。

应用场景:
在Spring中bean的创建,xml定义 scop=“prototype” 可以使用原型模式创建bean
在 doGetBean方法里,相对的有singleton单例创建

四、建造者模式

产品产品生产 分离
动作 与 对象 不应在一个类中,将具体的动作细节封装

  • 抽象建造者 Builder:规定建造中各种 “步骤” 的接口
  • 具体建造者 ConcreteBuilder:实际上 步骤 的执行者,不同的建造者实现步骤的细节逻辑不一样
  • 指挥者 Director:构建一个使用 Builder 接口的对象。主要有两个作用,一是隔离用户与对象的生产过程,二是负责控制产品对象的生产过程。
  • 产品角色 Product:要创造的对象实体

注重 建造 的过程,产品差异不大,区别体现在生产过程中。
不同的建造者,方法实现的细节不一样 、方法的执行顺序不一样
生产出不一样的产品,注重在拓展性

而抽象工厂模式关心工厂生产出什么样的产品,产品有明显区分,封装生产过程。
注重在松耦合

StringBuilder 应用:

  1. Appendable 定义了 append方法 – 抽象建造者
  2. AbstractStringBuilder 实现了 append 方法 – 具体建造者
  3. StringBuilder 不仅为具体建造者,也是 指挥者 。 建造者角度:它继承父类方法,指挥者角度:调用了方法。

五、适配器模式

被适配的类
适配器
用户

类、对象、接口三种适配模式

举例:转接头
让原本不适用的接口能够兼容调用
用户只关系适配器能否给出对应的接口,而不管适配器是怎么兼容用户本不支持的接口的。

  • 目标接口(Target):用户期望使用的抽象类或者接口
  • 适配器(Adapter):包装需要适配的对象,把原接口转换成目标接口。
  • 需要适配的类(Adaptee):需要适配的类。

1. 类适配器
适配器 继承 被适配类
可以通过重写父类方法等方式达到适配效果
缺点: 适配器和被适配类,二者由于继承关系耦合度变高了。

2. 对象适配器
持有实例 代替 继承 (合成复用原则)
适配器不再继承被适配类,而是在内部引入其实例再进行“兼容”。

3. 接口适配器
适配器实现接口,默认写好每一个方法空的或者其它。
用户在用接口适配器 的时候,只需要重写自己需要的方法覆盖,而不用针对某个接口实现所有的方法

应用场景:
SpringMvc中,每种Controller都配有一个适配器,这些适配器实现了同一个接口
不同的适配器针对对应的Controller都实现了 handle方法,DispatcherServlet 只关心执行handle方法,不管适配器是怎么利用Controller的。
DispatcherServlet 根据Controller的类型判断它应该调用何种适配器,然通过执行handle方法得到 ModelAndView

六、桥接模式

聚合代替继承
结构型模式

理论上:

抽象类 + 多个子类
实现类接口 + 多种实现类

抽象接口和具体实现分开。
在抽象类需要用到具体的实现类方法时,通过组合依赖实现类,而不是继承实现类。

比如:

做奶茶(抽象类):奶茶步骤(实现类接口)
做珍珠奶茶(抽象类子类):珍珠奶茶步骤(某个实现类)
做烧仙草(抽象类子类):烧仙草步骤(某个实现类
……
奶茶步骤(实现类接口)
奶茶步骤又有很多种:
珍珠奶茶步骤(某个实现类)、烧仙草步骤(某个实现类)、杨枝甘露步骤(某个实现类)……

最开始只知道做奶茶是有奶茶步骤的,但具体是什么,暂时不知道。
直到知道要做的是珍珠奶茶,就选用珍珠奶茶步骤,把具体的实现类注入抽象父类,然后在做珍珠奶茶的子类中super通过父类调方法。

不管是抽象类拓展到了多个,还是实现类有多少种手段,两方都只需要拓展新类,而不需要修改。
符合“开闭原则”。

应用举例:
JDBC属于不太标准的桥接模式
Driver 类中 DriverManager 要支持注册多种数据库链接,先指定一个Connection接口,不同数据库链接的实现类(ConnectionImpl)都实现了jdbc的Connection接口。
这样,在注册数据库链接时,只要是实现了jdbc的Connection接口的链接,都可以注册。
而DriverManager 没有抽象父类也没有子类,但作为抽象者它确实可以灵活地支持各种实现类。

七、装饰者模式

目的:动态地将新功能附加到对象上

实现:大肠包小肠、套娃……

  1. Component:被装饰者

抽象类

  1. ConcreteComponent:实际的被装饰者

Component的子类,一般有多种需要被装饰的对象

  1. Decorator:装饰者

抽象类,Component的子类,内聚了一个Component对象,并且定义了针对装饰者的方法

  1. ConcreteDecorator:实际的装饰者

Decorator的子类,同样也具有使用父类中Component对象的权利。

一般有多种类型的装饰者。

将需要装饰的对象,通过构造方法等方式,传入后得到一个新的对象。
即视为完成装饰这一个过程。

举例:

饮品

奶茶 extends 饮品
果汁extends 饮品
……

调料 extends 饮品 (内部包含一个饮品对象)

珍珠 extends 调料
燕麦 extends 调料
白糖 extends 调料
……

奶茶 drink = new 奶茶 ();
drink = new 珍珠(drink); 得到 带珍珠 的奶茶
drink = new 白糖(drink);得到 带白糖、带珍珠 的奶茶
……

使用的场景:

装饰者与被装饰者之间,具有某个或多个相同的特性

比如上述例子中计算加了多种调料后,奶茶的总价格是多少?
这里的相同特性就体现在他们都具有价格

应用场景:
JDK中InputStream就是被装饰者

八、组合模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上岸撒尿的鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值