设计模式之【中介者模式】,多对多关系降级为一对多关系的利器

news2024/12/17 12:43:06

文章目录

  • 一、什么是中介者模式
    • 1、中介者模式的优势
    • 2、中介者模式的缺点
    • 3、中介者模式的应用场景
    • 4、中介者模式的四大角色
    • 5、观察者模式和中介模式的区别
  • 二、实例
    • 1、中介者模式的一般写法
    • 2、租房中介案例
    • 3、智能家具案例
  • 三、源码中的中介者模式
    • 1、Timer

一、什么是中介者模式

中介者模式(Mediator Pattern)又称为调节者模式或调停者模式。用一个中介对象封装一系列的对象交互,中介者使各对象不需要显式的相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互,属于行为型模式。

中介者模式的核心思想是,通过中介者解耦系统各层次对象的直接耦合,层次对象的对外依赖通信统统交由中介者转发。

1、中介者模式的优势

(1)松散耦合
中介者模式通过把多个同事对象之间的交互封装到中介者对象里面,从而使得同事对象之间松散耦合,基本上可以做到互补依赖。这样一来,同事对象就可以独立地变化和复用,而不再像以前那样“牵一处而动全身”了。

(2)集中控制交互
多个同事对象的交互,被封装在中介者对象里面集中管理,使得这些交互行为发生变化的时候,只需要修改中介者对象就可以了,当然如果是已经做好的系统,那么就扩展中介者对象,而各个同事类不需要做修改。

(3)一对多关联转变为一对一的关联
没有使用中介者模式的时候,同事对象之间的关系通常是多对多的,引入中介者对象以后,中介者对象和同事对象的关系通常变成一对多,这会让对象的关系更容易理解和实现。

2、中介者模式的缺点

中介者模式中将原本多个对象直接的相互依赖变成了中介者和多个同事类的依赖关系。当同事类越多时,中介者就会越臃肿,变得复杂且难以维护。

3、中介者模式的应用场景

一般来说,同事类之间的关系是比较复杂的,多个同事类之间互相关联时,他们之间的关系会呈现为复杂的网状结构,这是一种过度耦合的架构,即不利于类的复用,也不稳定。例如在下图中,有六个同事类对象,假如对象1发生变化,那么将会有4个对象受到影响。如果对象2发生变化,那么将会有5个对象受到影响。也就是说,同事类之间直接关联的设计是不好的。
在这里插入图片描述
如果引入中介者模式,那么同事类之间的关系将变为星型结构,从下图中可以看到,任何一个类的变动,只会影响的类本身,以及中介者,这样就减小了系统的耦合。一个好的设计,必定不会把所有的对象关系处理逻辑封装在本类中,而是使用一个专门的类来管理那些不属于自己的行为。
在这里插入图片描述
中介者模式是用来降低多个对象和类之间的通信复杂性。这种模式通过提供一个中介类,将系统各层次对象间的多对多关系编程一对多关系,中介者对象可以将复杂的网状结构变成以调停者为中心的星型结构,达到降低系统的复杂性,提高可扩展性的作用。

若系统各层次对象之间存在大量的关联关系,即层次对象呈复杂的网状结构,如果直接让它们紧耦合通信,会造成系统结构变得异常复杂,且其中某个层次对象发生改变,则与其紧耦合的相应层次对象也需要进行修改,系统很难进行维护。而通过为该系统增加一个中介者层次对象,让其他各层次需对外通信的行为统统交由中介者进行转发,系统呈现以中介者为中心进行通讯的星型结构,系统的复杂性大大降低。

简单的说就是多个类相互耦合,形成了网状结构,则考虑使用中介者模式进行优化。总结中介者模式适用于以下场景:

  • 系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解;
  • 交互的公共行为,如果需要改变行为则可以增加新的中介者类。

4、中介者模式的四大角色

在这里插入图片描述
中介者模式包含以下主要角色:

  • 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
    -具体中介者(ConcreteMediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
  • 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
  • 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。

5、观察者模式和中介模式的区别

观察者模式有多种实现方式。虽然经典的实现方式没法彻底解耦观察者和被观察者,观察者需要注册到被观察者中,被观察者状态更新需要调用观察者的 update() 方法。但是,在跨进程的实现方式中,我们可以利用消息队列实现彻底解耦,观察者和被观察者都只需要跟消息队列交互,观察者完全不知道被观察者的存在,被观察者也完全不知道观察者的存在。

中介模式也是为了解耦对象之间的交互,所有的参与者都只与中介进行交互。而观察者模式中的消息队列,就有点类似中介模式中的“中介”,观察者模式的中观察者和被观察者,就有点类似中介模式中的“参与者”。

在观察者模式中,尽管一个参与者既可以是观察者,同时也可以是被观察者,但是,大部分情况下,交互关系往往都是单向的,一个参与者要么是观察者,要么是被观察者,不会兼具两种身份。也就是说,在观察者模式的应用场景中,参与者之间的交互关系比较有条理。

而中介模式正好相反。只有当参与者之间的交互关系错综复杂,维护成本很高的时候,我们才考虑使用中介模式。毕竟,中介模式的应用会带来一定的副作用,它有可能会产生大而复杂的上帝类。除此之外,如果一个参与者状态的改变,其他参与者执行的操作有一定先后顺序的要求,这个时候,中介模式就可以利用中介类,通过先后调用不同参与者的方法,来实现顺序的控制,而观察者模式是无法实现这样的顺序要求的。

二、实例

1、中介者模式的一般写法

// 抽象中介者
public abstract class Mediator {
    protected ConcreteColleagueA colleagueA;
    protected ConcreteColleagueB colleagueB;

    public void setColleageA(ConcreteColleagueA colleague) {
        this.colleagueA = colleague;
    }

    public void setColleageB(ConcreteColleagueB colleague) {
        this.colleagueB = colleague;
    }

    // 中介者业务逻辑
    public abstract void transferA();

    public abstract void transferB();
}

// 具体中介者
public class ConcreteMediator extends Mediator {
    @Override
    public void transferA() {
        // 协调行为:A 转发到 B
        this.colleagueB.selfMethodB();
    }

    @Override
    public void transferB() {
        // 协调行为:B 转发到 A
        this.colleagueA.selfMethodA();
    }
}
// 抽象同事类
public abstract class Colleague {
    protected Mediator mediator;

    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }
}
// 具体同事类
public class ConcreteColleagueA extends Colleague {
    public ConcreteColleagueA(Mediator mediator) {
        super(mediator);
        this.mediator.setColleageA(this);
    }

    // 自有方法:self-Method
    public void selfMethodA() {
        // 处理自己的逻辑
        System.out.println(String.format("%s:self-Method", this.getClass().getSimpleName()));
    }

    // 依赖方法:dep-Method
    public void depMethodA() {
        // 处理自己的逻辑
        System.out.println(String.format("%s:depMethod: delegate to Mediator", this.getClass().getSimpleName()));
        // 无法处理的业务逻辑委托给中介者处理
        this.mediator.transferA();
    }
}
// 具体同事类
public class ConcreteColleagueB extends Colleague {
    public ConcreteColleagueB(Mediator mediator) {
        super(mediator);
        this.mediator.setColleageB(this);
    }

    // 自有方法:self-Method
    public void selfMethodB() {
        // 处理自己的逻辑
        System.out.println(String.format("%s:self-Method", this.getClass().getSimpleName()));
    }

    // 依赖方法:dep-Method
    public void depMethodB() {
        // 处理自己的逻辑
        System.out.println(String.format("%s:depMethod: delegate to Mediator", this.getClass().getSimpleName()));
        // 无法处理的业务逻辑委托给中介者处理
        this.mediator.transferB();
    }
}
// 测试类
public class Test {
    public static void main(String[] args) {
        Mediator mediator = new ConcreteMediator();
        ConcreteColleagueA colleagueA = new ConcreteColleagueA(mediator);
        ConcreteColleagueB colleagueB = new ConcreteColleagueB(mediator);
        colleagueA.depMethodA();
        System.out.println("-------------------------");
        colleagueB.depMethodB();
    }
}

2、租房中介案例

现在租房基本都是通过房屋中介,房主将房屋托管给房屋中介,而租房者从房屋中介获取房屋信息。房屋中介充当租房者与房屋所有者之间的中介者。

类图如下:
在这里插入图片描述


//抽象同事类
public abstract class Person {
	protected String name;
	protected Mediator mediator;
	public Person(String name,Mediator mediator){
		this.name = name;
		this.mediator = mediator;
	}
}
//具体同事类 房屋拥有者
public class HouseOwner extends Person {
	public HouseOwner(String name, Mediator mediator) {
		super(name, mediator);
	}
	//与中介者联系
	public void constact(String message){
		mediator.constact(message, this);
	}
	//获取信息
	public void getMessage(String message){
		System.out.println("房主" + name +"获取到的信息:" + message);
	}
}
//具体同事类 承租人
public class Tenant extends Person {
	public Tenant(String name, Mediator mediator) {
		super(name, mediator);
	}
	//与中介者联系
	public void constact(String message){
		mediator.constact(message, this);
	}
	//获取信息
	public void getMessage(String message){
		System.out.println("租房者" + name +"获取到的信息:" + message);
	}
}
//抽象中介者
public abstract class Mediator {
	//申明一个联络方法
	public abstract void constact(String message,Person person);
}
//中介机构
public class MediatorStructure extends Mediator {
	//首先中介结构必须知道所有房主和租房者的信息
	private HouseOwner houseOwner;
	private Tenant tenant;
	public HouseOwner getHouseOwner() {
		return houseOwner;
	}
	public void setHouseOwner(HouseOwner houseOwner) {
		this.houseOwner = houseOwner;
	}
	public Tenant getTenant() {
		return tenant;
	}
	public void setTenant(Tenant tenant) {
		this.tenant = tenant;
	}
	public void constact(String message, Person person) {
		if (person == houseOwner) { //如果是房主,则租房者获得信息
			tenant.getMessage(message);
		} else { //反正则是房主获得信息
			houseOwner.getMessage(message);
		}
	}
}
//测试类
public class Client {
	public static void main(String[] args) {
		//一个房主、一个租房者、一个中介机构
		MediatorStructure mediator = new MediatorStructure();
		//房主和租房者只需要知道中介机构即可
		HouseOwner houseOwner = new HouseOwner("张三", mediator);
		Tenant tenant = new Tenant("李四", mediator);
		//中介结构要知道房主和租房者
		mediator.setHouseOwner(houseOwner);
		mediator.setTenant(tenant);
		tenant.constact("需要租三室的房子");
		houseOwner.constact("我这有三室的房子,你需要租吗?");
	}
}

3、智能家具案例

智能家居包括各种智能设备,闹钟、咖啡机、电视、窗帘等,主人要看电视时,各个设备可以协同工作,自动完成看电视的准备工作,比如流程未:闹钟响起->咖啡机开始做咖啡->窗帘自动落下->电视机开始播放。

//同事抽象类
public abstract class Colleague {
	private Mediator mediator;
	public String name;
	public Colleague(Mediator mediator, String name) {
		this.mediator = mediator;
		this.name = name;
	}
	public Mediator GetMediator() {
		return this.mediator;
	}
	public abstract void SendMessage(int stateChange);
}

//具体的同事类-闹钟
public class Alarm extends Colleague {
	//构造器
	public Alarm(Mediator mediator, String name) {
		super(mediator, name);
		//在创建Alarm 同事对象时,将自己放入到ConcreteMediator 对象中[集合]
		mediator.Register(name, this);
	}
	public void SendAlarm(int stateChange) {
		SendMessage(stateChange);
	}
	@Override
	public void SendMessage(int stateChange) {
		//调用的中介者对象的getMessage
		this.GetMediator().GetMessage(stateChange, this.name);
	}
}

// 具体同事类-咖啡机
public class CoffeeMachine extends Colleague {
	public CoffeeMachine(Mediator mediator, String name) {
		super(mediator, name);
		mediator.Register(name, this);
	}
	@Override
	public void SendMessage(int stateChange) {
		this.GetMediator().GetMessage(stateChange, this.name);
	}
	public void StartCoffee() {
		System.out.println("It's time to startcoffee!");
	}
	public void FinishCoffee() {

		System.out.println("After 5 minutes!");
		System.out.println("Coffee is ok!");
		SendMessage(0);
	}
}

// 具体同事类-窗帘
public class Curtains extends Colleague {
	public Curtains(Mediator mediator, String name) {
		super(mediator, name);
		mediator.Register(name, this);
	}
	@Override
	public void SendMessage(int stateChange) {
		this.GetMediator().GetMessage(stateChange, this.name);
	}
	public void UpCurtains() {
		System.out.println("I am holding Up Curtains!");
	}
}

// 具体同事类-电视
public class TV extends Colleague {
	public TV(Mediator mediator, String name) {
		super(mediator, name);
		mediator.Register(name, this);
	}
	@Override
	public void SendMessage(int stateChange) {
		this.GetMediator().GetMessage(stateChange, this.name);
	}
	public void StartTv() {
		System.out.println("It's time to StartTv!");
	}
	public void StopTv() {
		System.out.println("StopTv!");
	}
}

// 抽象中介
public abstract class Mediator {
	//将给中介者对象,加入到集合中
	public abstract void Register(String colleagueName, Colleague colleague);
	//接收消息, 具体的同事对象发出
	public abstract void GetMessage(int stateChange, String colleagueName);
	public abstract void SendMessage();
}
//具体的中介者类
public class ConcreteMediator extends Mediator {
	//集合,放入所有的同事对象
	private HashMap<String, Colleague> colleagueMap;
	private HashMap<String, String> interMap;

	public ConcreteMediator() {
		colleagueMap = new HashMap<String, Colleague>();
		interMap = new HashMap<String, String>();
	}

	@Override
	public void Register(String colleagueName, Colleague colleague) {
		colleagueMap.put(colleagueName, colleague);

		if (colleague instanceof Alarm) {
			interMap.put("Alarm", colleagueName);
		} else if (colleague instanceof CoffeeMachine) {
			interMap.put("CoffeeMachine", colleagueName);
		} else if (colleague instanceof TV) {
			interMap.put("TV", colleagueName);
		} else if (colleague instanceof Curtains) {
			interMap.put("Curtains", colleagueName);
		}
	}

	//具体中介者的核心方法
	//1. 根据得到消息,完成对应任务
	//2. 中介者在这个方法,协调各个具体的同事对象,完成任务
	@Override
	public void GetMessage(int stateChange, String colleagueName) {
		//处理闹钟发出的消息
		if (colleagueMap.get(colleagueName) instanceof Alarm) {
			if (stateChange == 0) {
				((CoffeeMachine) (colleagueMap.get(interMap
						.get("CoffeeMachine")))).StartCoffee();
				((TV) (colleagueMap.get(interMap.get("TV")))).StartTv();
			} else if (stateChange == 1) {
				((TV) (colleagueMap.get(interMap.get("TV")))).StopTv();
			}

		} else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) {
			((Curtains) (colleagueMap.get(interMap.get("Curtains"))))
					.UpCurtains();

		} else if (colleagueMap.get(colleagueName) instanceof TV) {//如果TV发现消息

		} else if (colleagueMap.get(colleagueName) instanceof Curtains) {
			//如果是以窗帘发出的消息,这里处理...
		}
	}

	@Override
	public void SendMessage() {
	}

}
// 测试类
public class ClientTest {

	public static void main(String[] args) {
		//创建一个中介者对象
		Mediator mediator = new ConcreteMediator();
		
		//创建Alarm 并且加入到  ConcreteMediator 对象的HashMap
		Alarm alarm = new Alarm(mediator, "alarm");
		
		//创建了CoffeeMachine 对象,并  且加入到  ConcreteMediator 对象的HashMap
		CoffeeMachine coffeeMachine = new CoffeeMachine(mediator,
				"coffeeMachine");
		
		//创建 Curtains , 并  且加入到  ConcreteMediator 对象的HashMap
		Curtains curtains = new Curtains(mediator, "curtains");
		TV tV = new TV(mediator, "TV");
		
		//让闹钟发出消息
		alarm.SendAlarm(0);
		coffeeMachine.FinishCoffee();
		alarm.SendAlarm(1);
	}

}

三、源码中的中介者模式

1、Timer

JDK中的Timer类,有很多schedule()的重载方法:
在这里插入图片描述
并且schedule方法都调用了私有的sched方法:

private void sched(TimerTask task, long time, long period) {
    if (time < 0)
        throw new IllegalArgumentException("Illegal execution time.");

    // Constrain value of period sufficiently to prevent numeric
    // overflow while still being effectively infinitely large.
    if (Math.abs(period) > (Long.MAX_VALUE >> 1))
        period >>= 1;

    synchronized(queue) {
        if (!thread.newTasksMayBeScheduled)
            throw new IllegalStateException("Timer already cancelled.");

        synchronized(task.lock) {
            if (task.state != TimerTask.VIRGIN)
                throw new IllegalStateException(
                    "Task already scheduled or cancelled");
            task.nextExecutionTime = time;
            task.period = period;
            task.state = TimerTask.SCHEDULED;
        }

        queue.add(task);
        if (queue.getMin() == task)
            queue.notify();
    }
}

我们发现,最终会将任务加入到一个queue队列中顺序执行。我们把这个队列中的所有对象称为“同事”。同事之间通信都是通过Timer进行协调的,Timer就承担了中介者的角色。

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

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

相关文章

Spring MVC 中的视图解析器是什么?如何配置它

当我们使用 Spring MVC 框架进行 Web 开发时&#xff0c;视图解析器&#xff08;View Resolver&#xff09;是一个非常重要的组件&#xff0c;它负责将控制器&#xff08;Controller&#xff09;所产生的逻辑视图名称&#xff08;Logical View Name&#xff09;转换成实际的视图…

Go语言环境搭建(内附网P下载地址)

一、Golang语言的官网 首先我们登录Golang的官方网站&#xff1a;https://golang.org/ 因为Google和中国的关系&#xff0c;直接登录Golang的官网&#xff0c;需要翻墙。 当然你也可以登录Golang的国内网站&#xff1a;https://golang.google.cn/ 二、下载 在Mac、Windows和L…

2023贵工程团体程序设计赛--赛后总结

本次比赛共27支队伍参加&#xff0c;总计135人&#xff0c;其中一支队伍为出题组&#xff08;不计入最后排名&#xff09;。实际参赛130人&#xff0c;5人缺考&#xff08;1人未加入题集&#xff09;。 1.人员分布 信息工程学院&#xff1a;22计科2支队伍&#xff0c;22软件6…

Python|Pyppeteer快速定位select下拉框(10)

前言 本文是该专栏的第10篇,结合优质项目案例持续分享Pyppeteer的干货知识,记得关注。 一般情况下,选中某个select下拉框,会出现一堆可选信息。如下图中的Country列表,点击列表会出现多个国家选择,如下图所示。 比如说,现在需要从这个Country列表中,快速选中某个国家…

2023新版Spring6全新讲解-SpringFramework介绍

SpringFramework介绍 一、官网地址阅读 https://spring.io/ 二、Spring的发展历史 三、Spring的概述 一个Java应用层程序&#xff0c;是由许多个类组成的&#xff0c;这些类之间必然存在依赖关系&#xff0c;当项目越来越大&#xff0c;依赖关系越来越复杂&#xff0c;需要一…

Jmeter连接不同类型数据库语法

Jmeter连接不同类型数据库语法 添加&#xff1a;配置原件->JDBC Connection Configuration variable name for created pool&#xff1a;自定义一个线程池变量名database Connection Configuration database URL: 填写数据库ip、端口、dbname等&#xff0c;但是不同数据库…

【UE4】从零开始制作战斗机(下:喷射尾焰随推进速度变化)

上一篇&#xff1a; 【UE4】从零开始制作战斗机&#xff08;中&#xff1a;飞机操控逻辑&#xff09;_Zhichao_97的博客-CSDN博客 效果 步骤 1. 新建一个Niagara发射器 选择新发射器 选择空模板 命名为“ThrusterEmitter” 2. 打开“ThrusterEmitter”&#xff0c;选中“发射…

真题详解(快速排序)-软件设计(八十一)

原创 真题详解(语法分析输入记号流)-软件设计&#xff08;八十)https://blog.csdn.net/ke1ying/article/details/130791934 COCOMOII基于____进行估算&#xff1f; 答案&#xff1a;源代码行数 2、0~7有8个索引&#xff0c;0~4是5个直接索引&#xff0c;磁盘块数据大小1kb字节…

Spring Cloud(Kilburn 2022.0.2版本)系列教程(二) 服务消费者(RestTemplate+Loadbalancer)

Spring Cloud(Kilburn 2022.0.2版本)系列教程(二) 服务消费者(RestTemplate+Loadbalancer) 一、服务消费 可以参考上节eurekaClientConsumer。 在启动类中,我们已经注入了一个restTemplate了,并且在上面增加了@LoadBalanced注解,这个是导入的org.springframework.cloud.cl…

001. 为啥用IDEA反编译没有擦除泛型?

你好&#xff0c;我是YourBatman&#xff1a;一个俗人&#xff0c;贪财好色。 &#x1f4da;前言 Java泛型是进阶高级开发必备技能之一&#xff0c;了解实现泛型的基本原理&#xff0c;有助于写出更优质的代码。 众所周知&#xff0c;Java是伪泛型&#xff0c;是通过类型擦除…

Redis哨兵集群搭建及其原理

Redis哨兵集群搭建及其原理 1.Redis哨兵1.1.哨兵原理1.1.1.集群结构和作用1.1.2.集群监控原理1.1.3.集群故障恢复原理1.1.4.小结 2.搭建哨兵集群2.1.集群结构2.2.准备实例和配置2.3.启动2.4.测试 3.RedisTemplate3.1.引入依赖3.2.配置Redis地址3.3.配置读写分离 1.Redis哨兵 R…

Centos8安装ffmpeg,使用mediamtx搭建RTSP流媒体服务器

文章目录 1、Centos安装ffmpeg2、使用mediamtx搭建媒体服务器 1、Centos安装ffmpeg 1、先安装epel-release yum install epel-release2、安装nux存储库 rpm -v --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/…

[NSSROUND#12]杂项记录

文章目录 [NSSRound#12 Basic]Bulbasaur[NSSRound#12 Basic]Secrets in Shadow[NSSRound#12 Basic]奇怪的tex文件[NSSRound#12 Basic]坏东西[NSSRound#12 Basic]ordinary forensics[NSSRound#12 Basic]Noisy Cube[NSSRound#12 Basic]ability[NSSRound#12 Basic]strange python …

数据结构课程设计——集合的交、并和差运算

集合的交、并和差运算 数据结构课程设计任务书 学生姓名&#xff1a; 专业班级&#xff1a; 软件工程 指导教师&#xff1a; 工作单位&#xff1a; 题 目: 集合的并、交和差运算 基础要求&#xff1a; 掌握数据结构与…

最全iOS 上架指南

一、基本需求信息。 1、苹果开发人员账户&#xff08;公司已经可以无需申请&#xff0c;需要开启开发者功能&#xff0c;每年99美元&#xff09; 2、开发好应用程序 二、证书 上架版本需要使用正式证书。 1、创建Apple Developer证书 2、上传证书Sign In - Apple 3、点击开发者…

pyqt5:py处理C语言格式数组和有符号数的转换(备忘录)

文章目录 1.问题&#xff1a;把下面的数组所表示的正弦波用曲线描绘出来。1.1 将C语言数组直接替换为py数组1.2 使用numpy读入数组1.3完整代码 2.从正弦波数据生成C数组2.1 正弦波数据2.2 负数转成16位带符号整型公式2.3 负数转成16位带符号整型 完整代码 3. 生成正弦波数据的代…

ASEMI代理英飞凌IPA65R650CE功率MOS管中文资料

编辑-Z IPA65R650CE是一款高性能功率晶体管&#xff0c;旨在满足现代电子应用日益增长的需求。这种先进的半导体器件提供了高效、低功耗和优异热性能的独特组合&#xff0c;使其成为广泛应用的理想选择&#xff0c;包括电源、电机驱动和可再生能源系统。 IPA65R650CE的主要功能…

失业五个月,终于有offer了!但这家公司的风评惨不忍睹,要接吗?

往年&#xff0c;程序员们找工作可以说是不怎么费力的&#xff0c;不少求职者还会比对几家offer&#xff0c;看薪酬、看加不加班、看通勤时间等等等等&#xff0c;最后选择自己最满意的那一家过去。 但是今年&#xff0c;情况确实完全不一样&#xff0c;用网友的话形容就是“往…

vs code ts运行、断点调试解决方案

序&#xff1a; 1、解决ts在vs code里直接运行&#xff0c;并在终端直接看结果 2、解决ts 断点调试问题&#xff08;博主这个调试算的上全网最简单的设置方法了&#xff09;。 3、ts-node : 无法加载文件 C:\Program Files\nodejs\ts-node.ps1,因为在此系统上禁去看这篇》ts-no…

Velocity模板与itextpdf联合生成pdf

pom <!-- velocity模板引擎 --><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.3</version></dependency><!-- itext7html转pdf --><depende…