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

news2024/12/24 21:00:44

适配器模式

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

手机充电需要将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("使用面粉、鸡蛋、牛奶等...制作一个基础蛋糕");
    }
}


抽象装饰器

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

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

//制作蛋糕的抽象装饰器
public abstract class CakeDecorator implements MakCake{
    private MakCake makCake;

    public CakeDecorator(MakCake makCake) {
        this.makCake = makCake;
    }

    @Override
    public void createCake() {
        makCake.createCake();
    }
}

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

给蛋糕添加水果

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();
}

先看结果 


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代码块包裹了,做成了并发安全
    }
}

代理模式

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

可以在不改变原有目标对象的基础上,对目标对象增加额外的扩展功能

静态代理

被代理对象与代理对象需要实现相同的接口或者是继承相同父类,因此要

定义一个接口或抽象类。

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动态代理

jdk动态代理是基于接口的一种代理方式,目标对象一定要实现接口。

原理是,利用反射机制,动态生成匿名类继承Proxy类并且实现了要代理的接口

cglib动态代理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/424814.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL 8.0 OCP (1Z0-908) 考点精析-性能优化考点1:sys.statement_analysis视图

文章目录MySQL 8.0 OCP (1Z0-908) 考点精析-性能优化考点1&#xff1a;sys.statement_analysis视图视图sys.statement_analysis各列定义视图sys.statement_analysis视图的定义视图sys.statement_analysis各列解释例题例题解析参考MySQL 8.0 OCP (1Z0-908) 考点精析-性能优化考点…

5G边缘计算网关用于智能消防安全

随着人们对智能消防安全的需求不断增长&#xff0c;5G边缘计算网关作为一种新型技术&#xff0c;已经被广泛应用于消防设备的智能监控和管理中。本文将介绍5G边缘计算网关在智能消防安全中的应用&#xff0c;并给出一个Python代码示例。 一、5G边缘计算网关在智能消防安全中的应…

OKR系统改变您的团队

使用Zoho Projects易于使用的OKR系统将雄心转化为行动。简化您计划、跟踪和报告团队目标的方式。 一、使用这个强大的OKR工具提升结果 1、自动组织团队的目标 在公司、部门、团队和个人层面创建和跟踪OKR&#xff0c;以实现真正的整体OKR管理。 2、实时跟踪进度 使团队能够使…

阻塞队列 BlockingQueue

阻塞队列&#xff08;BlockingQueue&#xff09;是一个支持两个附加操作的队列。这两个附加的操作支持阻塞的插入和移除的方法&#xff1a; 支持阻塞的插入方法&#xff1a;当队列满时&#xff0c;队列会阻塞插入元素的线程&#xff0c;直到队列不满&#xff1b;支持阻塞的移除…

HTML5 <header> 标签、HTML5 <html> 标签

HTML5 <header> 标签 实例 HTML5 &#xff0c;<header>标签用来表示介绍性的内容&#xff0c;即&#xff0c;定义了文档中的页眉&#xff0c;请参考下述示例&#xff1a; <article> 的页眉&#xff1a; <article><header><h1>Internet …

SpringSecurity之入门案例

前言 前面一篇文章讲了一些关于SpringSecurity的基本内容、两大核心模块以及学习他所需要的基本技能点。接下来&#xff0c;带大家进入到一个基本的入门案例&#xff01;&#xff01;&#xff01; 操作步骤 1、创建Springboot工程 首先通过idea开发工具&#xff0c;创建一个…

代码随想录_二叉树_leetcode669 108 538

leetcode 669. 修剪二叉搜索树 669. 修剪二叉搜索树 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果没…

翻译国外文章-整篇文章的翻译

chatgpt翻译是专业的吗 ChatGPT是一种AI语言模型&#xff0c;它可以用来执行各种自然语言处理任务&#xff0c;包括翻译。然而&#xff0c;ChatGPT的翻译结果并不是专业的翻译&#xff0c;因为该模型并不是专为翻译任务训练的。 虽然ChatGPT的翻译质量相对较高&#xff0c;但…

你了解C语言中的数组指针和函数指针吗?

如题&#xff0c;本篇文章重点讲解C语言中的数组指针和函数指针。这2种指针其实都不是很常用&#xff0c;个人感觉使用起来代码的可读性不是很高&#xff0c;但是还是需要了解一下。 数组指针 数组指针&#xff0c;即指向数组的指针&#xff0c;是用来存放数组的地址的。那如…

JavaScript对象类型之Array及Object

目录 一、Array &#xff08;1&#xff09;语法 &#xff08;2&#xff09;API 二、Object &#xff08;1&#xff09;语法 &#xff08;2&#xff09;特色&#xff1a;属性增删 &#xff08;3&#xff09;特色&#xff1a;this &#xff08;4&#xff09;特色&#xf…

公司测试员用例写得乱七八糟,测试总监制定了这份《测试用例编写规范》

统一测试用例编写的规范&#xff0c;为测试设计人员提供测试用例编写的指导&#xff0c;提高编写的测试用例的可读性&#xff0c;可执行性、合理性。为测试执行人员更好执行测试&#xff0c;提高测试效率&#xff0c;最终提高公司整个产品的质量。 一、范围 适用于集成测试用…

SAP MDG —— 使用DIF导入物料主数据 Part3 进阶篇

文章目录关于使用DIF处理物料主数据的相关信息IDOC 缩减IDOC 扩展物料编码的主键映射 Key Mapping主键映射和内部给号其他主键的主键映射值映射 Value Mapping将物料主数据导出为IDoc文件 - MATMAS / CLFMAS错误处理本章小结关于使用DIF处理物料主数据的相关信息 IDOC 缩减 场…

机器学习:基于KNN对葡萄酒质量进行分类

机器学习&#xff1a;基于KNN对葡萄酒质量进行分类 作者&#xff1a;i阿极 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏…

网盘工具助力律师团队文件管理

律师的日常工作离不开文件管理。文档管理对于律师而言是一门必修课&#xff0c;这也是日积月累的工作。良好的文件管理习惯可以帮助我们让工作流程化、标准化&#xff0c;助力知识管理&#xff0c;避免职业风险&#xff0c;提升团队工作效率。 好用的文件管理工具也可以帮助律师…

Python 实验三 控制语句

1.从键盘接收整数的一百分制成绩&#xff08;0到100)&#xff0c;要求输出其对应的成绩等级A-E。其中&#xff0c;90分&#xff08;包含&#xff09;以上为A&#xff0c;80-89&#xff08;均包含&#xff09;分为B&#xff0c;70-79(均包含&#xff09;分为C&#xff0c;60-69&…

[网络安全] Windows Server 设置文件屏蔽防止黑客利用漏洞上传特定类型的非法文件

我在负责网站运维期间&#xff0c;遇到过一次黑客利用网站内使用的开源文件上传工具漏洞上传非法文件&#xff08;可执行脚本&#xff09; 我是通过设置文件屏蔽来防止此类事件的再次发生。特在此做下记录。 文章目录前言一、黑客是怎么攻击我的二、我是怎么防范的2.1 Windows …

我学习网络安全的心得

我的学习心得&#xff0c;我认为能不能自学成功的要素有两点。 第一点就是自身的问题&#xff0c;虽然想要转行学习安全的人很多&#xff0c;但是非常强烈的想要转行学好的人是小部分。而大部分人只是抱着试试的心态来学习安全&#xff0c;这是完全不可能的。 所以能不能学成并…

Matplotlib 二维图像绘制方法

Matplotlib 二维图像绘制方法 介绍 Matplotlib 是支持 Python 语言的开源绘图库,因为其支持丰富的绘图类型、简单的绘图方式以及完善的接口文档,深受 Python 工程师、科研学者、数据工程师等各类人士的喜欢。本次实验课程中,我们将学会使用 Matplotlib 绘图的方法和技巧。…

GitHub的简介与Idea集成Git

六大基础功能 &#xff1a; 创建远程库、代码推送&#xff08;Push&#xff09;、代码拉取&#xff08;Pull&#xff09;、代码克隆&#xff08;Clone&#xff09;、SSH免密登录、Idea集成GitHub GitHub 网址&#xff1a;https://github.com/ 1.创建远程仓库 登录后的页面右上…

亚马逊云科技帮助BMW Financial Services设计和构建数据架构

BMW Group和亚马逊云科技于2020年宣布达成全面战略合作。在re:Invent2019上&#xff0c;BMW和亚马逊云科技展示了新的云数据中心平台&#xff0c;先是大致介绍了不同的数据平台原型&#xff0c;然后介绍了构建BMW Group云数据中心的过程。Amazon Data Lab使用亚马逊云科技的云数…