> 文章列表 > java设计模式(1) 适配器模式、装饰器模式

java设计模式(1) 适配器模式、装饰器模式

java设计模式(1) 适配器模式、装饰器模式

适配器模式

适配器就是一种适配中间件,它存在于不匹配的了两者之间,用于连接两者,使不匹配变得匹配。

手机充电需要将220V的交流电转化为手机锂电池需要的5V直流电

知识补充:手机充电器输入的电流是交流,通过变压整流输出电流是直流的。。

类适配器

️2️⃣Adaptee 源角色   :220V的交流电(家用电一般是220V)  

//家用电压
public class HomeElectri {//输出220v交流电,AC指的是交流电public int outputAC220V() {int output = 220;return output;}
}

1️⃣Target 目标角色 :  手机锂电池需要的5V直流电

目标类只需要定义方法,由适配器来转化:

//手机充电接口
public interface MobileCharge {//需要5v的直流电//DC指的是直流电int outputDC5V();
}

3️⃣Adapter 适配器角色  :手机充电器

我为什么这么写,又去继承又去实现的?

          作为适配器,需要拿到俩边的资源。通过继承拿到源角色的能力(输出220V)通过实现接口,知道自己的目的角色。

//手机的适配器(手机充电器)
public class PhoneAdapter extends HomeElectri implements MobileCharge {@Overridepublic int outputDC5V() {int output = outputAC220V();return (output / 44);}
}

对象适配器

不继承HomeElectri 类,而是持有HomeElectri 类的实例

提供一个包装类Adapter,这个包装类包装了一个Adaptee的实例,从而此包装类能够把Adaptee的API与Target类的API链接起来。

//手机的适配器(手机充电器)
public class PhoneAdapter implements MobileCharge {HomeElectri homeElectri;public PhoneAdapter(HomeElectri homeElectri) {this.homeElectri = homeElectri;}@Overridepublic int outputDC5V() {int output = homeElectri.outputAC220V();return (output / 44);}
}
PhoneAdapter adapter=new PhoneAdapter(new HomeElectri());
System.out.println("输出电压: "+adapter.outputDC5V());


接口适配器

接口的适配器是这样的:接口中往往有多个抽象方法,但是我们写该接口的实现类的时候,必须实现所有这些方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,

如:MouseListener是一个接口,里面有鼠标的各种事件

public interface MouseListener extends EventListener {public void mouseClicked(MouseEvent e);public void mousePressed(MouseEvent e);public void mouseReleased(MouseEvent e);public void mouseEntered(MouseEvent e);public void mouseExited(MouseEvent e);
}

此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法

MouseAdapter有2个特点

第一:它是抽象类。

第二:每个方法MouseAdapter都做了空实现

public abstract class MouseAdapter implements MouseListener, MouseWheelListener, MouseMotionListener {public void mouseClicked(MouseEvent e) {}public void mousePressed(MouseEvent e) {}public void mouseReleased(MouseEvent e) {}public void mouseEntered(MouseEvent e) {}public void mouseExited(MouseEvent e) {}public void mouseWheelMoved(MouseWheelEvent e){}public void mouseDragged(MouseEvent e){}public void mouseMoved(MouseEvent e){}
}

而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行

addMouseListener()这个方法需要MouseListener的一个参数

JButton jButton = new JButton("点我有惊喜");
jButton.addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {System.out.println("惊不惊喜,意不意外");}
});

装饰器模式

装饰器模式核心思想

在不改变原有类的基础上给类新增额外的功能,符合开闭原则: 对扩展开放,对修改关闭

1.装饰模式是继承的一个替代模式,通过组的方式完成继承的功能,但却避免了继承的侵入性

2.装饰类和被装饰类可以独立发展,不会相互耦合

原有的:

//制作蛋糕
public interface MakCake {//cake -蛋糕void createCake();
}

它的实现类

public class MakeCakeImpl implements MakCake {//制作蛋糕的通用基础逻辑@Overridepublic void createCake() {System.out.println("使用面粉、鸡蛋、牛奶等...制作一个基础蛋糕");}
}


抽象装饰器

抽象装饰器: 通用的装饰的装饰器,其内部必然,有一个属性指向,其实现一般是一个抽象类

被装饰类和所有的装饰类必须实现同一个接口,而且必须持有被装饰的对象,可以无限装饰

//制作蛋糕的抽象装饰器
public abstract class CakeDecorator implements MakCake{private MakCake makCake;public CakeDecorator(MakCake makCake) {this.makCake = makCake;}@Overridepublic void createCake() {makCake.createCake();}
}

具体装饰器角色:向“制作蛋糕”添加新的职责

给蛋糕添加水果

public class FruitAddDecorator extends AbsCakeDecorator{public FruitAddDecorator(MakCake makCake) {super(makCake);}@Overridepublic void createCake() {super.createCake();decorateMethod();}// 定义自己的修饰逻辑private void decorateMethod() {System.out.println("加一份新鲜的水果,如草莓...");}
}

给蛋糕添加饼干

public class BiscuitAddDecorator extends AbsCakeDecorator {public BiscuitAddDecorator(MakCake makCake) {super(makCake);}@Overridepublic void createCake() {super.createCake();decorateMethod();}// 定义自己的修饰逻辑private void decorateMethod() {System.out.println("加一份好吃的饼干,如奥利奥...");}
}

测试

public static void main(String[] args) {//制作最基础的蛋糕面饼MakCake cake = new MakeCakeImpl();//为蛋糕添加水果cake= new FruitAddDecorator(cake);cake.createCake();
}

控制台:


无限装饰?

什么是无限装饰?使用装饰器模式一层一层的对最底层被包装类进行功能扩展了。 

  • 对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,得到功能更为强大的对象。
public static void main(String[] args) {//制作最基础的蛋糕面饼MakCake cake = new MakeCakeImpl();//为蛋糕添加水果cake= new FruitAddDecorator(cake);// 第二次修饰,蛋糕添加饼干cake = new BiscuitAddDecorator(cake);cake.createCake();
}

先看结果 


new 构造器分析

如上,再new装饰器的时候,构造器做啥了 

 //为蛋糕添加水果cake= new FruitAddDecorator(cake);

1 进入FruitAddDecorator 

2 AbsCakeDecorator中的makCake赋值为MakeCakeImpl的实例

-----------------------------------

 代码再走一行

 // 第二次修饰,蛋糕添加饼干cake = new BiscuitAddDecorator(cake);

3. 进入BiscuitAddDecorator

4.又进入父类AbsCakeDecorator,AbsCakeDecorator中的makCake赋值为FruitAddDecorator的实例


调用方法分析

public static void main(String[] args) {//制作最基础的蛋糕面饼MakCake cake = new MakeCakeImpl();//为蛋糕添加水果cake= new FruitAddDecorator(cake);// 第二次修饰,蛋糕添加饼干cake = new BiscuitAddDecorator(cake);cake.createCake();
}
分析完前面的new构造器之后,cake.createCake()做啥了???

此时cake是BiscuitAddDecorator的引用

1. 会先调用BiscuitAddDecorator的createCake方法,

2. 走super的createCake(),进入其父类AbsCakeDecorator的方法

3.1 从idea提示看的出此时makCake是FruitAddDecorator的实例,那么接着进入FruitAddDecorator的createCake()

3.2.走super的createCake(),再进入AbsCakeDecorator,此时makCake是MakeCakeImpl

的实例

 3.3.进入MakeCakeImpl,控制台打印输出

打印完成后回到3.1,再打印输出

 再回到第一步,BiscuitAddDecorator的createCake(),打印输出


在java哪里见过

这是我在学习安全的并发容器类时用到过的,比如

List<Object> synchronizedList = Collections.synchronizedList(new ArrayList<>());

我们来看SynchronizedList,它是Collections的静态内部类。

public class Collections {static class SynchronizedList<E> extends SynchronizedCollection<E> implements List<E> {final List<E> list;SynchronizedList(List<E> list) {super(list);this.list = list;}public void add(int index, E element) {synchronized (mutex) {list.add(index, element);}}public E remove(int index) {synchronized (mutex) {return list.remove(index);}}//...很多方法都用synchronized代码块包裹了,做成了并发安全}
}

代理模式

代理模式的特点在于隔离:隔离调用类和被调用类的关系,通过一个代理类去调用