参考: 地址
动态代理详见: 动态代理、 Spring AOP
适配器模式
适配器模式,把一个类的接口变成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。也是一种包装类,与装饰模式同样具有包装的功能。
优缺点
优点:
- 可以让任何两个没有关联的类一起允许
- 提高了类的复用,即使该类的接口标准不符合系统需要,而通过适配器就可以使用
缺点:
- 过多的使用会导致系统凌乱
适用场景
- 想使用一个已存在的类,而其接口不符合需求
- 需要创建一个可重用的类,即与接口无关的类
模式的应用
- JDK 中的 IO 库大量使用了适配器模式,如 ByteArrayInputStream(ByteArrayOutputStream)适配器类实现了 InputStream 接口,将一个 byte 数组的接口适配成 InputStream 流处理器的接口;还有 FileOutputStream、Reader等。
- Spring 的 AOP 不同Advice类型和对应的拦截器之间
角色分配
- 目标接口
- 被适配者(已有的目标接口实现类)
- 适配者
- 适配器
适配器模式的实现
1.目标接口
interface Target{
void connection();
}
2.被适配者
class Typec implements Target{
public void connection(){
System.out.println("使用Type-c数据线连接...");
}
}
3.适配者
class Micro{
public void connection(){
System.out.println("使用Micro USB数据线连接...");
}
}
4.适配器
(1)类适配器(继承被适配类,同时实现标准接口)
class TypecAdapter extends Micro implements Target{
public void connection(){
System.out.println("使用转接头...");
super.connection();//调用父类的方法
}
}
(2)对象适配器
class TypecAdapter implements Target{
private Target target;
public TypecAdapter(Target target){
this.target = target;
}
public void connection(){
System.out.println("使用转接头...");
target.connection();
}
}
区别
类适配器:对象继承的方式,静态定义
对象适配器:对象组合的方法
5.使用
(1)使用类适配器
//原功能
Target target = new Typec();
target.connection();
//适配后功能
Target adapter = new TypecAdapter();
adapter.connection();
(2)使用对象适配器
Target adapter = new TypecAdapter(new Micro());
adapter.connection();
注:尽量使用对象的适配器模式,少用继承的同时,不能过度使用适配器模式
组合模式
组合模式,将对象组合成树形结构以表示部分以及整体的层次结构,使得我们对单个对象和组合对象的使用具有一致性。
优缺点
优点:
- 高层模块调用简单
- 节点自由增加
缺点:
- 子叶和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则
适用场景
需求中需要体现部分与整体层次结构的时候,如树形菜单,文件、文件夹的管理
角色分配
- 抽象/接口类
- 具体树枝类
- 具体树叶类(都实现抽象类)
组合模式的实现
1.抽象类
public abstract Employee{
private String name;
private String dept;
public Employee(String name,String dept){
this.name = name;
this.dept = dept;
}
public abstract void add(Employee e);
public abstract void print();
}
2.具体树枝类,老板类
public Boss extends Employee{
private List<Employee> temp = new ArrayList<Employee>();
public Boos(String name,String dept){
super(name,dept);
}
public void add(Employee e){
temp.add(e);
}
public void print(int depth){
System.out.println("第"+depth+"级职员:"+name)
for(Employee e : temp){
e.print(depth+1);
}
}
}
3.具体树叶类,员工
public Staff extends Employee{
public Staff(String name,String dept){
super(name,dept);
}
public void add(Employee e){}
public void print(int depth){
System.out.println(""第"+depth+"级职员:"+name")
}
}
4.使用
Employee boss = new Boss("MOKE","Boss")
boss.add(new Boss("Robert","CEO"));
boos.add(new Boss("John","CEO");)
CEO1.add(new Staff("Laura","Marketing"));
CEO2.add(new Staff("Bob","Marketing"));
装饰者模式
装饰者模式,以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
优点
- 相比继承更加的灵活,允许动态增加或删除一个装饰的功能。
角色分配
- 抽象构件角色
- 具体构件角色
- 装饰角色(持有抽象构件角色的实例)
- 具体装饰角色
装饰者模式的实现
1.抽象构建角色
interface Student{
public void study();
}
2.具体构件角色
class MOKE implements Student{
public void study(){
System.out.println("开始学习...");
}
}
3.装饰角色
class Decorator implements Student{
private Student stu;
public Decorator(People people){
this.people = people;
}
public void study(){
stu.study();
}
}
4.具体装饰角色
class MathDecorator extends Decorator{
public MathDecorator(Student stu){
super(stu);
}
public void study(){
super.study();
System.out.println("学习数学");
}
}
class ComputerDecorator extends Decorator{
public ComputerDecorator(Student stu){
super(stu);
}
public void study(){
super.study();
System.out.println("学习计算机");
}
}
5.使用
MOKE p = new MathDecorator(new ComputerDecorator(new MOKE()));//声明变量要尽量使用顶层的超类
p.study();
/*
开始学习...
学习计算机
学习数学
*/
简单装饰者模式
1.只有一个具体构件角色:可以去掉抽象构件角色
class Decorator extends MOKE{//直接继承具体构件角色
private Student stu;
public Decorator(People people){
this.people = people;
}
public void study(){
stu.study();
}
}
2.只有一个装饰角色(多个具体构件角色):可以去掉装饰角色
class MathDecorator implements Student{//直接实现抽象构件
private Student student;
public MathDecorator(Student stu){
this.student = stu
}
public void study(){
student.study();
System.out.println("学习数学");
}
}
3.具体构件角色和具体装饰角色只有一个:继承形式
半透明装饰者模式
在实现抽象构件的装饰角色中,定义了新的方法
class MathDecorator extends Decorator{
public MathDecorator(Student stu){
super(stu);
}
public void study(){
super.study();
System.out.println("学习数学");
}
public void eat(){ System.out.println("学完数学,食堂吃饭");
}
}
使用:
MathDecorator mathdecorator = new MathDecorator(new ComputerDecorator(new MOKE()));//生成顶层超类,调用eat会出错,需要向下转型,所以直接使用子类
mathdecorator.study();
mathdecorator.eat();
外观模式
外观模式,为子系统中的一组接口提供了一个统一的访问接口,这个接口使得子系统更容易被访问或者使用。
优点
- 客户端与子系统直接解耦,便于子系统的扩展与维护
- 客户端不需要知道子系统内部实现就可以使用
- 子系统能更好的划分对内对外提供的不同功能
适用场景
4. 为复杂的模块提供外界访问的模块
5. 在层析结构中,可以定义每一层的入口
角色分配
6. 子系统角色(多、复杂)
7. 门面角色
8. 客户角色(通过门面角色操作子系统)
外观模式的实现
1.子系统角色(多个模块)
(1)cpu
public class CPU{
public void start(){
System.out.println("CPU is running...");
}
public void shutDown(){
System.out.println("CPU is shutDown...");
}
}
(2)Disk
public class Disk{
public void start(){
System.out.println("Disk is running...");
}
public void shutDown(){
System.out.println("Disk is shutDown...");
}
}
2.门面角色
public class Computer{
private CPU cpu;
private Disk disk;
public Computer(){
cpu = new CPU();
disk = new Disk();
}
public void start(){
System.out.println("Computer starting...");
cpu.start();
disk.start();
System.out.println("Computer had started.");
}
public void shutDown(){
System.out.println("Computer ending...");
cpu.shutDown();
disk.shutDown();
System.out.println("Computer had shutDown");
}
}
3.客户角色(使用)
public class Cilent{
public static void mian(String[] args){
Computer computer = new Computer();
computer.start();
System.out.println("==========");
computer.shutDown();
}
}
代理模式
外观模式是对子系统中多个类的封装,而代理模式是代理一个类,即对一个类的封装。真正的业务功能还是由目标类来实现,代理类只是用于扩展、增强目标类的行为。
静态代理和动态代理区别
- 静态代理:手写或工具生成代理类,在程序运行前就已经编译好了
- 动态代理:在程序运行期间根据需要动态创建代理类和实例
应用
- Spring的AOP
- Mybatis缓存机制对连接池的管理
角色分配
- 抽象角色
- 被代理角色(抽象角色实现类)
- 代理角色
- 客户端
代理模式的实现
静态代理
1.抽象角色
public interface Movie{
void play();
}
2.被代理角色
public class RealMovie implements Movie{
public void play(){
System.out.println("正在放映:惊奇队长");
}
}
3.静态代理角色
public class Cinema implements Movie{
RealMovie movie;
public Cinema(RealMovie movie){
this.movic = movie;
}
public void play(){
advertisement(true);//前置增强
movie.play();//具体功能,委托目标类
advertisement(false);//后置增强
}
public void advertisement(boolean playing)
if(playing)
System.out.println("电影快要开始了,请自备3D眼镜");
else
System.out.println("电影已经结束,请检查随身物品");
}
4.客户端(使用)
Movie realmovie = new RealMovie();
Movie movie = new Cinema(realmovie);
movie.play();
动态代理
相关接口和类:InvocationHandler(Interface)接口和Proxy(Class)类
1.抽象角色、被代理角色(同上)
2.动态代理角色
public class Cinema implements InvocationHandler{
private Object proxied;
public ProxyHandler(Object proxied){
this.proxied = proxied;
}
public Object invoke(Object proxy,Method,Object[] args) throws Throwable{
System.out.println("电影快要开始了,请自备3D眼镜");
Object obj = method.invoke(proxied, args);
System.out.println("电影已经结束,请检查随身物品");
}
}
3.客户端(使用)
Movie realmovie = new RealMovie();
Movie proxyMovic = Proxy.newProxyInstance(Movie.class.getClassLoader(),new Class[] {Movie.class},new ProxyHandler(realmovie ));
//三大参数:实例对象,实例方法,实例方法的参数
proxyMovic.play();