纵向扩展:增强更多的方法
动态代理:动态不同为类的对象创建代理。增强代理。灵活实现:
实现方式
- JDK动态代理:只可对接口创建代理
- CGLIB动态代理:可对接口、类创建代理
整个动态代理,需要代理的接口 ,new出来被代理的对象。也就是 动态给我们创建一个$proxy,也就是不用我们自己去创建这个类。因此 需要 invocationhandler 进行动态代理。
把需要增强的功能代码在 invocationhandler上实现就行。
基于接口的动态代理。代理对象给我就行。
Girl tony1 = (Girl) TonyCompany.proxy(tc);
th.dating(tony1);
这里就会产生一个代理的实现类
这都是动态代理应该调用到的, 包括权限校验等等。
cglib动态代理
A powerful, high performance and quality Code Generation Library, It is used to extend JAVA classes and implements interfaces at runtime. 一个高层次的java字节码生成和转换的api库.
生成字节码。
ASM:一个低层次的字节码操作库
主要作用
在运行期为类、接口生成动态代理对象。
以达到不改动原类代码而实现功能增强的目的
使用和实现方式和jdk中动态代理是很像的。
代理的实现类。
会到具体的方法上面去。
责任链模式
最常见的应用就是springmvc中的使用。
http web请求处理,请求过来后将经过转码、解析、参数封装、鉴权….一系列的处理(责任),而且要经过多少处理是可以灵活调整的。
责任链:所有的处理者,都加入到这个链式,一个处理完后,转给下一个。、
1、抽象出责任接口,具体责任逻辑实现接口。
2、根据处理过程需要,将具体实现组合成链。
3、使用者使用链。
每一次请求的链条是可能不同的。抽象出变化的部分具体的接口。
当然各种实现 可以采用 链表,也可以采用数组来实现。 在netty中就使用的链表。
和装饰的区别 还是在不用把被装饰者包含起来。 并且重点在于 流水线
如果当我们不需要下个链条是 不用执行下面代码就可以了。
chain.process(request);
适配器模式
应用在 使用者依赖的接口与提供者的接口不匹配时,就加一层适配,而不改两端的代码。
使用转换器来将不符合的代码进行转换。
适配器的模式 将不同的接口连起来,但是针对的是类进行兼容。然后适配
外观(门面)模式
应用场景:
使用方要完成一个功能,需要调用提供方的多个接口、方法,调用过程复杂时,我们可以再提供一个高层接口(新的外观),将复杂的调用过程向使用方隐藏。适配器模式的变种。
例如一键换机,快速进行操作。这些都是
设计原则:迪米特原则,最少知识原则
只需要装饰起来 中介开。他会把所有要做的存储起来,这个在应用中使用的非常多,我们只需要一点就行,其他的,都帮我们做了。
观察者模式
这个模式在我们开发过程中也会遇到很多把,微信公众号,关注就可以收到推送的消息,取消关注,就不会再收到。 以及在什么消息中间件中的思想也是采用 也就是发布订阅。
变化之处:观察者会变,观察者的数量会变。
不变:主题的代码要不受观察者变化的影响。
定义了对象之间一对多的依赖关系,当一端对象改变状态时,它的所有依赖者都会收到通知并自动更新(被调用更新方法)。
也称为:监听模式、发布订阅模式。提供一种对象之间松耦合的设计方式。
设计原则:为了交互对象之间的松耦合设计而努力!
在jdk中提供给了我们观察者模式的通用实现。
Java.util. Observable 可被观察的(主题),具体主题扩展它。
java.util.Observer 观察者接口,具体观察者实现该接口。
项目开发中 我之前用到的就是 android 应用启动时,将所有需要启动的类,都做一个启动方法。
命令模式
应用场景
系统设计一个命令行界面,用户可输入命令来执行某项功能。 系统的功能会不断添加,命令也会不断增加。
对于命令不同的实现, 而且不固定 大量时,动态的添加
采用map的方式,去解决 这种 if else的方式,
并且将具体的功能给抽象出来,扩展成不同的格式来处理
这个和策略模式很像,但是不一样。
命令模式:
以命令的方式,解耦调用者与功能的具体实现者,降低系统耦合度,提供了灵活性。
适用场景:交互场景
实例:Servlet Controller 线程池
而策略模式更加简单一点 ,不会来存储这个变化的部分。从而达到实现大量的变化。
策略模式侧重的是一个行为的多个算法实现,可互换算法。
命令模式侧重的是为多个行为提供灵活的执行方式。
状态模式
一个类对外提供了多个行为,同时该类对象有多种状态,不同状态下对外的行为的表现不同
状态的流转,需要一个状态去控制。
根据状态去控制行为。
不同的状态下,这四种种操作将有不同的表现。
如在没有支付状态下,用户在咖啡机上点退款、购买、取咖啡,和在已支付的状态下做这三个操作。
命令模式的变化部分 就是状态,所以需要把状态 抽象化。成为接口。对应的方法。 这也是整个设计模式需要,通过接口 或者抽象类去实现。
对比 状态模式-命令模式-策略模式
策略模式侧重的是一个行为的多个算法实现,可互换算法
命令模式侧重的是为多个行为提供灵活的执行方式。
状态模式,应用于状态机的情况。
设计原则:区分变与不变,隔离变化
设计原则:面向接口编程
设计原则:多用组合,少用继承
两个以上的模式进行组合,复合模式
桥接模式
一个画图程序,可以画各种颜色不同形状的图形。
比如有红、黄、蓝三种颜色
形状有方形、圆、三角形
圆可以是红圆、黄圆、蓝圆
会从两个维度发生变化:形状、颜色
解决的也是多维度上的变化
会导致类爆炸的, 发生变化的主要是颜色和图形 都会变化。
能抽象 但是组合起来是比较麻烦的。
而桥接模式就是解决这种 情况的。
任其在两个维度各自变化,为这两个维度搭个
桥,让它们可以融合在一起:桥接模式
组合:将抽象组合在一起(桥接)
桥接:将多个维度的变化以
抽象的方式组合在一起。使
用者面向抽象。各维度间解
耦,可自由变化。 这里就要利用抽象类进行处理了。
单例模式
减少类对象的创建
饥汉式
在实例化时就初始化好类对象。
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
public class Singleton {
private static Singleton instance;
static {
instance = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
懒汉式
在使用时才去创建类对象,因此可能需要考虑线程安全等。
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
缺点:实例化后就不应该再同步了,效率低。
其实根据需要 还是实现采用双重检查
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
注意: volatile关键字修饰很关键
优点:线程安全;延迟加载;效率较高。
public class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE =
new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
优点:避免了线程不安全,延迟加载,效率高。
原理:类的静态属性只会在第一次加载类的时候初始化。在这里,JVM帮助我们保证了线程的安
全性,在类进行初始化时,别的线程是无法进入的。
只要调用getinstance就不会创建 singletoninstance类的。
用枚举的方式
public enum Singleton {
INSTANCE;
public void whateverMethod() {
} }
模板方法模式
当我们设计一个类时,我们能明确它对外提供的某个方法的内部执行步骤, 但一些步骤,不同的子类有不同的行为时
public abstract class Game {
protected abstract void initialize();
protected abstract void startPlay();
protected abstract void endPlay();
//模板方法
public final void play(){
//初始化游戏
initialize();
//开始游戏
startPlay();
//结束游戏
endPlay();
}
}
优点
1、封装不变部分,扩展可变部分。
2、提取公共代码,便于维护。
3、行为由父类控制,子类实现。
适用场景:
1、有多个子类共有的方法,且逻辑相同。
2、重要的、复杂的方法,可以考虑作为模板方法。
总结
设计模式总结
创建型模式
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
包括
- 工厂模式(Factory Pattern)
- 抽象工厂模式(Abstract Factory Pattern)
- 单例模式(Singleton Pattern)
- 建造者模式(Builder Pattern)
- 原型模式(Prototype Pattern)
结构型模式
这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
包括
- 适配器模式(Adapter Pattern)
- 桥接模式(Bridge Pattern)
- 组合模式(Composite Pattern)
- 装饰器模式(Decorator Pattern)
- 外观模式(Facade Pattern)
- 享元模式(Flyweight Pattern)
- 代理模式(Proxy Pattern)
行为型模式
这些设计模式特别关注对象之间的通信。
包括:
- 责任链模式(Chain of Responsibility Pattern )
- 命令模式(Command Pattern)
- 解释器模式(Interpreter Pattern)
- 迭代器模式(Iterator Pattern)
- 中介者模式(Mediator Pattern)
- 备忘录模式(Memento Pattern)
- 观察者模式(Observer Pattern)
- 状态模式(State Pattern)
- 空对象模式(Null Object Pattern)
- 策略模式(Strategy Pattern)
- 模板模式(Template Pattern)
- 访问者模式(Visitor Pattern)
设计原则总结
- 变化隔离原则:找出变化,分开变化和不变的 隔离,封装变化的部分,让其他部分不受它的影响。
- 面向接口编程 依赖倒置 隔离,封装变化的部分,让其他部分不受它的影响。 隔离变化的方式 使用者使用接口,提供者实现接口。“接口”可以是超类!
-
开闭原则:对修改闭合,对扩展开放 隔离变化的方式
-
单一职责原则 方法设计的原则