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 {

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

代理模式

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

XML复习

目录什么是XMLXML中的内容可以干什么XML文件的创建以及其格式XML的文档约束-DTD约数XML的文档约束-schema约束Dom4J 解析XML 文档什么是XML XML 全称(extensible Markup Lanage) 可扩展标记语言它是一种数据的表示形式, 可以存储复杂的数据格式以及我们自己定义的格式.XML经常…

windows安装ubuntu时错误WslRegisterDistribution failed with error: 0x8007023e的解决方法

cmd或者powershell安装&#xff0c;或者打开linux时 莫名的出现了如下错误&#xff1a; Installing, this may take a few minutes... WslRegisterDistribution failed with error: 0x8007023e Error: 0x8007023e {Application Error} The exception s (0x尝试了很多的方法都不…

Qt图片显示有波纹

现象 Qt中当渲染显示的分辨率比原图片分辨率小时&#xff0c;就会有波纹。如下图所示&#xff0c;左边是正常显示&#xff0c;右边衬衫那里产生严重的波纹。这种波纹在计算机图形学叫摩尔纹&#xff0c;这是纹理贴图采样出现走样的现象&#xff0c;纹理分辨率过大时就会出现这…

解决Windows微信和 PowerToys 的键盘管理器冲突

Windows开机之后PowerToys能正常使用, 但是打开微信之后设置好的快捷键映射就全部失效了 打开微信 -> 左下角三条杠 -> 设置 -> 快捷键 首先我把微信的快捷键全部清空了,发现还是没用 然后发现了设置里默认勾选了检测快捷键,我在想程序肯定是一直在后台检测,而powerTo…

可以计算“如何把程序写好”吗?

其实简单理解这个问题就是“可不可以用机器来判断人的程序写得好不好&#xff1f; 后面我查阅了资料&#xff0c;历史上有一个对计算机领域影响颇深的可计算理论&#xff0c;“计算”应该就来源于这里。其实继续深挖还能找出很多涉及计算机本源的有趣的知识&#xff0c;比如图…

异构计算给我们带来了哪些思考?

虽然异构计算的快速发展给企业创新带来了更加强大的算力支撑&#xff0c;但真正推动异构计算的高速发展和应用落地&#xff0c;笔者认为还需要在以下三个方面做好功课。 从2022年火爆全球的元宇宙&#xff0c;到今年的ChatGPT&#xff0c;以人工智能为代表的科学技术正在创造出…

Unity Animation -- 改进动画效果

使用曲线&#xff08;Curves&#xff09;改善动画 在上一篇笔记中&#xff08;Unity Animation -- Overview_亦枫Leonlew的博客-CSDN博客&#xff09;&#xff0c;我们制作了简单的小球弹跳的动画&#xff0c;但这个动画看起来很不自然&#xff0c;小球的弹跳看起来就像是不受…

Vue3信息提示(Modal)

Vue2信息提示&#xff08;Modal&#xff09; 可自定义设置以下属性&#xff1a; 标题描述&#xff08;title&#xff09;&#xff0c;类型&#xff1a;string&#xff0c;默认 Title 内容描述&#xff08;content&#xff09;&#xff0c;类型&#xff1a;string&#xff0c;…

盲盒经济下与社交电商结合,打造电商卖货新模式

如今&#xff0c;盲盒经济正在从线下延伸到线上&#xff0c;从潮流玩具扩展到美妆、食品、服装、数码等领域&#xff0c;形成了一种新的电商生态。 什么是盲盒电商&#xff1f; 盲盒电商是一种电商行业的营销模式&#xff0c;通过发起盲盒活动或拆盲盒&#xff0c;让参与者不…

MongoDB 查询文档(3)

我们之前讲解过&#xff0c;查询文档的语法&#xff1a; db.collection.find(query, projection, options) 其中 query 代表的是查询过滤器&#xff0c;projection 代表的是文档返回的字段&#xff0c;options 代表的是用于查询的其他选项&#xff1b; 我们已经对query进行了…

Ubuntu16.04虚拟机下安装Qt5.10.0

首先安装虚拟机Vmware,具体参见: Win10安装Vmware+Ubuntu16.04_芯片-嵌入式的博客-CSDN博客 安装完成后,下载qt-opensource-linux-x64-5.10.0.run,使用U盘来实现win10和ubuntu虚拟机之间的文件传输,cp到一个目录后,sudo ./qt-opensource-linux-x64-5.10.0.run进行运行,…

I/O多路转接之select

初识select 系统提供select函数来实现多路复用输入/输出模型.* select系统调用是用来让我们的程序监视多个文件描述符的状态变化的; * 程序会停在select这里等待&#xff0c;直到被监视的文件描述符有一个或多个发生了状态改变;select函数原型 select的函数原型如下: #include …

SpringCloud 使用sentinel

一、添加依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> 二、配置文件配置地址 spring:cloud:sentinel:transport:dashboard: localhost:8080三…

【CSS】课程网站 网格商品展示 模块制作 ① ( 网格商品展示模块盒子模型测量及样式 | 顶部文本标题盒子测量及样式 | 代码示例 )

文章目录一、网格商品展示模块盒子模型测量及样式1、盒子尺寸测量2、标题盒子尺寸测量和样式3、左侧文本盒子尺寸测量和样式4、右侧文本盒子尺寸测量和样式二、顶部文本标题盒子代码示例1、HTML 标签结构2、CSS 样式3、展示效果绘制矩形框中的部分 : 一、网格商品展示模块盒子…

【服务器数据恢复】NTFS分区被格式化如何恢复数据?

服务器数据恢复环境&故障&#xff1a; 误操作格式化服务器RAID5磁盘阵列下的分区&#xff08;NTFS文件系统&#xff09;。 服务器数据恢复过程&#xff1a; 1、将故障服务器连接到北亚企安备份服务器上&#xff0c;将故障服务器的所有硬盘设置为脱机状态&#xff0c;然后以…

什么是中间件?

一、什么是中间件&#xff1f; 1、百度百科 中间件是介于应用系统和系统软件之间的一类软件&#xff0c;它使用系统软件所提供的基础服务&#xff08;功能&#xff09;&#xff0c;衔接网络上应用系统的各个部分或不同的应用&#xff0c;能够达到资源共享、功能共享的目的。目…

手写简易 Spring(二)

文章目录手写简易 Spring&#xff08;二&#xff09;1. 扩展 BeanFactory 接口2. 实现资源加载器&#xff0c;从 Spring.xml 解析和注册 Bean 对象1. 核心实现类 XmlBeanDefinitionReader3. 实现应用上下文&#xff0c;自动识别、资源加载、扩展机制1. 应用上下文2. 核心实现类…

java基础之抽象类与接口

文章目录1.抽象方法和抽象类2.抽象类的作用3.接口4.接口和抽象类的异同5.面向接口编程1.抽象方法和抽象类 抽象方法和抽象类必须使用abstract修饰符来定义&#xff0c;有抽象方法的类只能被定义成抽象类&#xff0c;抽象类里可以没有抽象方法。 抽象类必须使用abstract修饰符来…

【Redis学习】Redis入门概述

Redis是什么 Redis:REmote Dictionary Server(远程字典服务器) 官网介绍&#xff1a;The open source, in-memory data store used by millions of developers as a database, cache, streaming engine, and message broker.&#xff08;被数百万开发人员用作数据库、缓存、流…

在云服务部署前后端以及上传数据库

1.上传数据库(sql文件) 首先建立一个目录&#xff0c;用于存放要部署的sql文件&#xff0c;然后在此目录中进入mysql 进入后建立一个数据库&#xff0c;create database 数据库名 完成后&#xff0c;通过select * from 表名可以查到数据说明导入成功。 2.部署Maven后端 将Ma…