赞
踩
适配器就是一种适配中间件,它存在于不匹配的了两者之间,用于连接两者,使不匹配变得匹配。
手机充电需要将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 {
-
- @Override
- public 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;
- }
-
- @Override
- public 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() { @Override public void mouseClicked(MouseEvent e) { System.out.println("惊不惊喜,意不意外"); } });
装饰器的核心就是在不改原有类的基础上给类新增功能。。
1.装饰模式是继承的一个替代模式,通过组合的方式完成继承的功能,但却避免了继承的侵入性
2.装饰类和被装饰类可以独立发展,不会相互耦合
原有的:
//制作蛋糕 public interface MakCake { //cake -蛋糕 void createCake(); }它的实现类
public class MakeCakeImpl implements MakCake { //制作蛋糕的通用基础逻辑 @Override public void createCake() { System.out.println("使用面粉、鸡蛋、牛奶等...制作一个基础蛋糕"); } }
抽象装饰器(Decorator): 通用的装饰的装饰器,其实现一般是一个抽象类。
被装饰类[MakeCakeImpl]和所有的装饰类【CakeDecorator、FruitAddDecorator、BiscuitAddDecorator ] 必须实现同一个接口[MakCake]
1、而且必须持有被装饰的对象[MakCake的引用],这样,装饰器可以调用MakeCake的方法,也可以选择性的添加自己的行为。
2、可以无限装饰,在运行时为对象添加多个装饰器,从而组合出不同的功能
- //制作蛋糕的抽象装饰器
- public abstract class CakeDecorator implements MakCake{
- private MakCake makCake;
-
- public CakeDecorator(MakCake makCake) {
- this.makCake = makCake;
- }
-
- @Override
- public void createCake() {
- makCake.createCake();
- }
- }
装饰器实现的重点是对抽象类继承接口方式的使用,同时设定被继承的接口可以通过构造函数传递其实现类,由此增加扩展性并重写方法里可以实现此部分父类实现的功能。
具体装饰器(Concrete Decorator):向“制作蛋糕”添加新的职责
给蛋糕添加水果
public class FruitAddDecorator extends AbsCakeDecorator{ public FruitAddDecorator(MakCake makCake) { super(makCake); } @Override public void createCake() { super.createCake(); decorateMethod(); } // 定义自己的修饰逻辑 private void decorateMethod() { System.out.println("加一份新鲜的水果,如草莓..."); } }给蛋糕添加饼干
public class BiscuitAddDecorator extends AbsCakeDecorator { public BiscuitAddDecorator(MakCake makCake) { super(makCake); } @Override public 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();
- }
先看结果,打印的顺序和编写代码的顺序是一致的
说实话:看着好像java的缓存流,对基层的io流做了装饰
最后一行调用的时候: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(),打印输出
new 构造器分析
如上,再new装饰器的时候,构造器做啥了
//为蛋糕添加水果 cake= new FruitAddDecorator(cake);1 进入FruitAddDecorator
2 AbsCakeDecorator中的makCake赋值为MakeCakeImpl的实例
-----------------------------------
代码再走一行
// 第二次修饰,蛋糕添加饼干 cake = new BiscuitAddDecorator(cake);3. 进入BiscuitAddDecorator
4.又进入父类AbsCakeDecorator,AbsCakeDecorator中的makCake赋值为FruitAddDecorator的实例
Decorator模式的目的就是把一个一个的附加功能,用Decorator的方式给一层一层地累加到原始数据源上,最终,通过组合获得我们想要的功能
例子一:给FileInputStream
增加缓冲和解压缩功能,用Decorator模式写出来如下:
- // 创建原始的数据源:
- InputStream fis = new FileInputStream("test.gz");
- // 增加缓冲功能:
- InputStream bis = new BufferedInputStream(fis);
- // 增加解压缩功能:
- InputStream gis = new GZIPInputStream(bis);
BufferedInputStream
和GZIPInputStream
,它们实际上都是从FilterInputStream
继承的,这个FilterInputStream
就是一个抽象的Decorator。
Decorator模式有什么好处?它实际上把核心功能和附加功能给分开了。
核心功能指
FileInputStream
这些真正读数据的源头,附加功能指加缓冲、压缩、解密这些功能。而具体如何附加功能,由调用方自由组合,从而极大地增强了灵活性。
例子二:安全的并发容器类SynchronizedList,比如
List<Object> synchronizedList = Collections.synchronizedList(new ArrayList<>());
场景举例一:
假设我们需要渲染一个HTML的文本,但是文本还可以附加一些效果,比如加粗、变斜体、加下划线等。为了实现动态附加效果,可以采用Decorator模式。
场景举例二:
假设电商平台上有各种商品可以卖,有些商品需要提供定制化的服务,如礼品包装、定制化贺卡等等。这时候可以使用装饰器模式,对商品进行装饰以提供相应服务。
场景举例三:
一个煎饼摊,煎饼可以加鸡蛋、加香肠,计算最终的价格,我们如何实现?
代理模式的特点在于隔离:隔离调用类和被调用类的关系,通过一个代理类去调用。代理模式主要目的是控制对象的访问,并在不改变原对象的前提下增加额外的功能(如权限检查、日志记录),也常用于延迟加载,只有当真正需要的时候才会创建真实对象。
被代理对象与代理对象需要实现相同的接口或者是继承相同父类,因此要
定义一个接口或抽象类。
public interface Calculator { int add(int i, int j); }接口的实现类
public class CalculatorImpl implements Calculator { @Override public int add(int i, int j) { int result = i + j; return result; } }
现在想要在add方法执行之前,执行后打印返回结果。做一个增强,很容易想到这么做。。但是一看就不符合开闭原则。。
增加一个代理类,在代理类里打印日志,在代理类里去调用目标对象的方法
- public class CalculatorProxy implements Calculator{
- private CalculatorImpl calculatorImpl;
-
- public CalculatorProxy(CalculatorImpl calculatorImpl) {
- this.calculatorImpl = calculatorImpl;
- }
-
- @Override
- public int add(int i, int j) {
- System.out.println("[日志] add 方法执行前,参数是:" + i + "," + j);
- int result = calculatorImpl.add(i, j);
- System.out.println("[日志] add 方法结束,运算结果是:" + result);
- return result;
- }
-
- }
测试:
- public static void main(String[] args) {
- //创建目标对象
- CalculatorImpl calculator = new CalculatorImpl();
- //创建代理对象
- CalculatorProxy calculatorProxy = new CalculatorProxy(calculator);
- //使用代理对象去调用方法,隔离目标对象和客户端
- calculatorProxy.add(1,3);
- }
jdk动态代理是基于接口的一种代理方式,目标对象一定要实现接口。
原理是,利用反射机制,动态生成匿名类继承Proxy类并且实现了要代理的接口
通过页面传来的type值,需要返回不同的下拉框内容,我们先用很多个if...else实现。如下:
- public class Test {
- public static void main(String[] args) {
- String type = "选择基点";
- String[] conext = getSelectConext(type);
- //打印返回的string数组
- Arrays.stream(conext).forEach(System.out::println);
- }
-
- public static String[] getSelectConext(String type) {
- if (type.equals("判断条件")) {
- return new String[]{"大于", "小于", "等于", "大于等于", "小于等于"};
- } else if (type.equals("点击方式")) {
- return new String[]{"左键单击", "左键双击", "右键单击", "右键双击"};
- } else if (type.equals("选择基点")) {
- return new String[]{"左上", "左下", "中心", "右上", "右下"};
- }
- return null;
- }
- }
缺点:当传入不同的type类型的时候,我们需要继续增加else if。。。
创建一个接口,该接口针对不同的type。会使用不同的实现类返回对应的内容
- //下拉框内容
- public interface ComboBoxContent {
- public String[] dropDownlist();
- }
创建完成后,就是感觉类有点爆炸(多)。但是可以很好的满足隔离性和扩展性需求,方便承接不断新增的需求
三个实现类
//判断条件 public class JudgeConditionComboBox implements ComboBoxContent{ @Override public String[] dropDownlist() { return new String[]{"大于", "小于", "等于", "大于等于", "小于等于"}; } } //--------------------------------------- //点击方式 public class ClickWayComboBox implements ComboBoxContent{ @Override public String[] dropDownlist() { return new String[]{"左键单击", "左键双击", "右键单击", "右键双击"}; } } //--------------------------------------- //选择基点 public class BasePointComboBox implements ComboBoxContent{ @Override public String[] dropDownlist() { return new String[]{"左上", "左下", "中心", "右上", "右下"}; } }
- public class ComboBoxStrategyFactory {
- private static final Map<String, ComboBoxContent> map = new HashMap<>();
-
- static {
- map.put("判断条件", new JudgeConditionComboBox());
- map.put("点击方式", new ClickWayComboBox());
- map.put("选择基点", new BasePointComboBox());
- }
-
- public static ComboBoxContent getStrategy(String type) {
- return map.get(type);
- }
- }
改造之前
----------------------------------
改造后:
策略模式的控制类[Context]主要是外部可以传递不同的策略实现,再通过统一的方法执行策略计算。
- //上下文类
- public class ContextComboBox {
- private ComboBoxContent comboBoxContent;
-
- public ContextComboBox(ComboBoxContent comboBoxContent) {
- this.comboBoxContent = comboBoxContent;
- }
-
- //真正对外暴露的接口
- public String[] getComboBoxList() {
- //通过不同接口实现类调用具体的策略
- return comboBoxContent.dropDownlist();
- }
- }
比如:awt的布局管理器,用户在构建界面的时候指定要使用的布局管理器
观察者模式的定义:观察者模式结构中主要包括观察目标(Object)和观察者(Observer)
一个目标对象可被多个观察者对象同时监听,使得每当目标对象状态变化时,所有依赖于它的观察者对象都会得到通知并被自动更新。此种模式通常被用来实时事件处理系统。
Subject里面有要通知的观察者们,定义为一个<Observer> observers 。
- public class Subject {
-
- private List<Observer> observers = new ArrayList<Observer>();
- private int state;
-
- public int getState() {
- return state;
- }
-
- public void setState(int state) {
- this.state = state;
- // 通知所有的观察者,调用notifyall()方法
- notifyAllObservers();
- }
-
- public void add(Observer observer) {
- observers.add(observer);
- }
-
- public void notifyAllObservers() {
- for (Observer observer : observers) {
- // 更新每一个观察者查看的信息
- observer.update();
- }
- }
- }
这些观察者都得有update方法,这样在被通知的时候就能去更新了。
怎么保证Observer每一个都有这个方法呢,是不是可以考虑把Observer去继承一个抽象类,里面写一个update()抽象方法,让每一个观察者去继承这个Observer抽象类即可。
Observer抽象类
- public abstract class Observer {
- // 把一个类放进抽象类中意义:其实与普通类中放进去道理一样
- public Subject subject;
- // 定义抽象类,由实现类实现
- public abstract void update();
- }
第一个观察者:二进制
//二进制 public class BinaryObserver extends Observer { public BinaryObserver(Subject subject) { this.subject = subject; this.subject.add(this); } @Override public void update() { //二进制方式输出数字 System.out.println("二进制观察者,接收到新的数字: " + subject.getState() + ";并做出对应的处理,处理结果:" + Integer.toBinaryString(subject.getState())); } }第二个观察者:八进制
//八进制 public class OctalObserver extends Observer { public OctalObserver(Subject subject) { this.subject = subject; this.subject.add(this); } @Override public void update() { //八进制方式输出数字 System.out.println("八进制观察者,接收到新的数字: " + subject.getState() + ";并做出对应的处理,处理结果:" + Integer.toOctalString(subject.getState())); } }第三个观察者:十六进制
//十六进制 public class HexaObserver extends Observer { public HexaObserver(Subject subject) { this.subject = subject; this.subject.add(this); } @Override public void update() { //十六进制方式输出数字 System.out.println("十六进制观察者,接收到新的数字: " + subject.getState() + ";并做出对应的处理,处理结果:" + Integer.toHexString(subject.getState())); } }
- public class Test {
- public static void main(String[] args) {
- Subject subject = new Subject();
- //添加二进制观察者
- new BinaryObserver(subject);
- //添加八进制观察者
- new OctalObserver(subject);
- //添加十六进制观察者
- new HexaObserver(subject);
-
- System.out.println("First state change: 15");
- subject.setState(15);
- System.out.println("------------------------------------------");
- System.out.println("Second state change: 10");
- subject.setState(10);
- System.out.println("------------------------------------------");
- System.out.println("Third state change: 5");
- subject.setState(5);
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。