适配器(变压器)模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。
中国市电220V,如果买个国产笔记本去国外,国外电压110V如何使用呢?幸好有了笔记本电源适配器帮忙
/**
* Created by IntelliJ IDEA.
* Date: 2008-8-2 14:43:46
* 源角色
*/
public class Adaptee {
public int get220v(){
return 220;
}
}
/**
* Created by IntelliJ IDEA.
* Date: 2008-8-2 14:43:23
* 目标角色
*/
public interface Target {
int get110v();
int get220v();
}
/**
* Created by IntelliJ IDEA.
* Date: 2008-8-2 14:43:07
* 适配器角色:扩展源角色,实现目标角色,从而使得目标角色改动时候,不用改动源角色,只要改动适配器
*/
public class Adapter extends Adaptee implements Target{
public int get110v(){
return 110;
}
}
/**
* Created by IntelliJ IDEA.
* Date: 2008-8-2 15:00:31
* 客户端
*/
public class Client {
public static void main(String rags[]) {
new Client().test();
}
public void test() {
Target target = new Adapter();
int v1 = target.get110v();
int v2 = target.get220v();
}
}
适配器通过扩展源角色,同时实现目标接口,从而满足了同时提供220v,110v电压的要求。
鲁智深的故事
和尚要做什么呢?吃斋、念经、打坐、撞钟、习武等。如果设计一个和尚接口,给出所有的和尚都需要实现的方法,那么这个接口应当如下:
public interface 和尚 {
public void 吃斋();
public void 念经();
public void 打坐();
public void 撞钟();
public void 习武();
public String getName();
}
显然,所有的和尚类都应当实现接口所定义的全部方法,不然就根本通不过JAVA语言编辑器。像下面的鲁智深类就不行。
public class 鲁智深 implements 和尚{
public void 习武(){
拳打镇关西;
大闹五台山;
大闹桃花村;
火烧瓦官寺;
倒拔垂杨柳;
}
public String getName(){
return "鲁智深";
}
}
由于鲁智深只实现了getName()和习武()方法,而没有实现任何其他的方法。因此,它根本就通不过Java语言编译器。鲁智深类只有实现和尚接口的所有的方法才可以通过Java语言编译器,但是这样一来鲁智深就不再是鲁智深了。以史为鉴,可以知天下。研究一下几百年前鲁智深是怎么剃度成和尚的,会对Java编程有很大的启发。不错,当初鲁达剃度,众僧说:“此人形容丑恶、相貌凶顽,不可剃度他",但是长老却说:”此人上应天星、心地刚直。虽然时下凶顽,命中驳杂,久后却得清净。证果非凡,汝等皆不及他。”
原来如此!看来只要这里也应上一个天星的话,问题就解决了!使用面向对象的语言来说,“应”者,实现也;“天星”者,抽象类也。
public abstract class 天星 implements 和尚 {
public void 吃斋(){}
public void 念经(){}
public void 打坐(){}
public void 撞钟(){}
public void 习武(){}
public String getName(){
return null;
}
}
鲁智深类继承抽象类“天星”
public class 鲁智深 extends 天星{
public void 习武(){
拳打镇关西;
大闹五台山;
大闹桃花村;
火烧瓦官寺;
倒拔垂杨柳;
}
public String getName(){
return "鲁智深";
}
}
这个抽象的天星类便是一个适配器类,鲁智深实际上借助于适配器模式达到了剃度的目的。此适配器类实现了和尚接口所要求的所有方法。但是与通常的适配器模式不同的是,此适配器类给出的所有的方法的实现都是“平庸”的。这种“平庸化”的适配器模式称作缺省适配模式。
在很多情况下,必须让一个具体类实现某一个接口,但是这个类又用不到接口所规定的所有的方法。通常的处理方法是,这个具体类要实现所有的方法,那些有用的方法要有实现,那些没有用的方法也要有空的、平庸的实现。
这些空的方法是一种浪费,有时也是一种混乱。除非看过这些空方法的代码,程序员可能会以为这些方法不是空的。即便他知道其中有一些方法是空的,也不一定知道哪些方法是空的,哪些方法不是空的,除非看过这些方法的源代码或是文档。
缺省适配模式可以很好的处理这一情况。可以设计一个抽象的适配器类实现接口,此抽象类要给接口所要求的每一种方法都提供一个空的方法。就像帮助了鲁智深的“上应天星”一样,此抽象类可以使它的具体子类免于被迫实现空的方法。
JDK 中有大量使用适配器模式的案例,清单 11 大致列举了一些类。
清单 11. 使用适配器模式的类
java.util.Arrays#asList()
javax.swing.JTable(TableModel)
java.io.InputStreamReader(InputStream)
java.io.OutputStreamWriter(OutputStream)
javax.xml.bind.annotation.adapters.XmlAdapter#marshal()
javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal()
JDK1.1 之前提供的容器有 Arrays,Vector,Stack,Hashtable,Properties,BitSet,其中定义了一种访问群集内各元素的标准方式,称为 Enumeration(列举器)接口,用法如清单 12 所示。
清单 12.Enumeration 接口实现方式
Vector v=new Vector();
for (Enumeration enum =v.elements(); enum.hasMoreElements();) {
Object o = enum.nextElement();
processObject(o);
}
JDK1.2 版本中引入了 Iterator 接口,新版本的集合对象(HashSet,HashMap,WeakHeahMap,ArrayList,TreeSet,TreeMap, LinkedList)是通过 Iterator 接口访问集合元素的,用法如清单 13 所示。
清单 13. Iterator 接口实现方式
List list=new ArrayList();
for(Iterator it=list.iterator();it.hasNext();)
{
System.out.println(it.next());
}
这样,如果将老版本的程序运行在新的 Java 编译器上就会出错。因为 List 接口中已经没有 elements(),而只有 iterator() 了。那么如何将老版本的程序运行在新的 Java 编译器上呢? 如果不加修改,是肯定不行的,但是修改要遵循“开-闭”原则。我们可以用 Java 设计模式中的适配器模式解决这个问题。清单 14 所示是解决方法代码。
清单 14. 采用适配器模式
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
public class NewEnumeration implements Enumeration
{
Iterator it;
public NewEnumeration(Iterator it)
{
this.it=it;
// TODO Auto-generated constructor stub
}
public boolean hasMoreElements()
{
// TODO Auto-generated method stub
return it.hasNext();
}
public Object nextElement()
{
// TODO Auto-generated method stub
return it.next();
}
public static void main(String[] args)
{
List list=new ArrayList();
list.add("a");
list.add("b");
list.add("C");
for(Enumeration e=new NewEnumeration(list.iterator());e.hasMoreElements();)
{
System.out.println(e.nextElement());
}
}
}
清单 14 所示的 NewEnumeration 是一个适配器类,通过它实现了从 Iterator 接口到 Enumeration 接口的适配,这样我们就可以使用老版本的代码来使用新的集合对象了。
Java I/O 库大量使用了适配器模式,例如 ByteArrayInputStream 是一个适配器类,它继承了 InputStream 的接口,并且封装了一个 byte 数组。换言之,它将一个 byte 数组的接口适配成 InputStream 流处理器的接口。
我们知道 Java 语言支持四种类型:Java 接口,Java 类,Java 数组,原始类型(即 int,float 等)。前三种是引用类型,类和数组的实例是对象,原始类型的值不是对象。也即,Java 语言的数组是像所有的其他对象一样的对象,而不管数组中所存储的元素类型是什么。这样一来的话,ByteArrayInputStream 就符合适配器模式的描述,是一个对象形式的适配器类。FileInputStream 是一个适配器类。在 FileInputStream 继承了 InputStrem 类型,同时持有一个对 FileDiscriptor 的引用。这是将一个 FileDiscriptor 对象适配成 InputStrem 类型的对象形式的适配器模式。查看 JDK1.4 的源代码我们可以看到清单 15 所示的 FileInputStream 类的源代码。
清单 15. FileInputStream 类
Public class FileInputStream extends InputStream{
/* File Descriptor - handle to the open file */
private FileDescriptor fd;
public FileInputStream(FileDescriptor fdObj) {
SecurityManager security = System.getSecurityManager();
if (fdObj == null) {
throw new NullPointerException();
}
if (security != null) {
security.checkRead(fdObj);}fd = fdObj;
}
public FileInputStream(File file) throws FileNotFoundException {
String name = file.getPath();
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
fd = new FileDescriptor();
open(name);
}
//其它代码
}
}
同样地,在 OutputStream 类型中,所有的原始流处理器都是适配器类。ByteArrayOutputStream 继承了 OutputStream 类型,同时持有一个对 byte 数组的引用。它一个 byte 数组的接口适配成 OutputString 类型的接口,因此也是一个对象形式的适配器模式的应用。
FileOutputStream 继承了 OutputStream 类型,同时持有一个对 FileDiscriptor 对象的引用。这是一个将 FileDiscriptor 接口适配成 OutputStream 接口形式的对象型适配器模式。
适配器模式使用注意事项
充当适配器角色的类就是:实现已有接口的抽象类;
为什么要用抽象类?此类是不要被实例化的。而只充当适配器的角色,也就为其子类提供了一个共同的接口,但其子类又可以将精力只集中在其感兴趣的地方。
适配器模式中被适配的接口 Adaptee 和适配成为的接口 Target 是没有关联的,Adaptee 和 Target 中的方法既可以是相同的,也可以是不同的。
适配器在适配的时候,可以适配多个 Apaptee,也就是说实现某个新的 Target 的功能的时候,需要调用多个模块的功能,适配多个模块的功能才能满足新接口的要求。
适配器有一个潜在的问题,就是被适配的对象不再兼容 Adaptee 的接口,因为适配器只是实现了 Target 的接口。这导致并不是所有 Adaptee 对象可以被使用的地方都能是使用适配器,双向适配器解决了这个问题。
优点
适配器模式也是一种包装模式,它与装饰模式同样具有包装的功能,此外,对象适配器模式还具有委托的意思。总的来说,适配器模式属于补偿模式,专用来在系统后期扩展、修改时使用。
缺点
过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
适配器模式应用场景
在软件开发中,也就是系统的数据和行为都正确,但接口不相符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。比如在需要对早期代码复用一些功能等应用上很有实际价值。适用场景大致包含三类:
1、已经存在的类的接口不符合我们的需求;
2、创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作;
3、在不对每一个都进行子类化以匹配它们的接口的情况下,使用一些已经存在的子类。
类适配器和对象适配器的权衡
类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式。
对于类适配器,由于适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一起工作,因为继承是静态的关系,当适配器继承了Adaptee后,就不可能再去处理 Adaptee的子类了。
对于对象适配器,一个适配器可以把多种不同的源适配到同一个目标。换言之,同一个适配器可以把源类和它的子类都适配到目标接口。因为对象适配器采用的是对象组合的关系,只要对象类型正确,是不是子类都无所谓。
对于类适配器,适配器可以重定义Adaptee的部分行为,相当于子类覆盖父类的部分实现方法。
对于对象适配器,要重定义Adaptee的行为比较困难,这种情况下,需要定义Adaptee的子类来实现重定义,然后让适配器组合子类。虽然重定义Adaptee的行为比较困难,但是想要增加一些新的行为则方便的很,而且新增加的行为可同时适用于所有的源。
对于类适配器,仅仅引入了一个对象,并不需要额外的引用来间接得到Adaptee。
对于对象适配器,需要额外的引用来间接得到Adaptee。
建议尽量使用对象适配器的实现方式,多用合成/聚合、少用继承。当然,具体问题具体分析,根据需要来选用实现方式,最适合的才是最好的。
适配器模式的优点
更好的复用性
系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。
更好的扩展性
在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。
适配器模式的缺点
过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
相关推荐
Java 设计模式之适配器模式的详解 适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的接口,使得原本不能一起工作的类可以一起工作。适配器模式也称为变压器模式或包装...
本文档主要介绍了连续电流模式(CCM)下的反激变压器设计方法,及其多路输出电流有效值的计算。 首先,反激变换器的工作原理包括了两个基本工作状态:当开关管Q1导通时,能量开始在变压器初级侧储存;而当Q1截止时...
在众多设计模式中,“接口型模式”特指那些关注于接口设计和实现的设计模式,适配器模式便是其中的核心之一。 **适配器模式**的本质在于允许不同接口的对象协同工作。它通过将一个类的接口转换为另一个类期望的接口...
本资源包包含了一系列经典的设计模式课件及案例代码,涵盖了工厂模式、门面模式、适配器模式等多个重要的设计模式。 首先,我们来看看工厂模式。工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。在...
### Java设计模式——变压器模式详解 #### 一、引言 设计模式是在软件设计中针对常见问题提出的标准化解决方案。在面向对象编程中,设计模式帮助开发者编写可复用且易于理解的代码。Java设计模式涵盖了多种不同的...
看到一个园子里的朋友写了一篇ASP.NET的适配器设计模式的文章。其中提到了把输入的电压转换成灯泡适合的电压,这样才能使灯泡正常工作。正巧,我也在学习设计模式,其中翻看了一下秦小波写的《设计模式与禅》这本书...
总结以上,RCC变压器设计涉及了谐振电路理论、工作模式、变压器设计、控制策略、效率优化、热管理、安全标准等多个方面,是电源工程中的关键技术之一。"RCC变压器设计.xls"可能是对这一复杂过程的简化和辅助,帮助...
本篇参考设计针对一款超薄型65瓦(W)的笔记本适配器,详细介绍了该适配器的原理和构造,以下是相关知识点的详细阐述。 一、适配器的基本原理与构造 笔记本适配器通常由以下几个主要部分构成: 1. 输入滤波部分:...
变压器模式是Java设计模式中一个非常实用的概念,它通过适配器类解决了接口不兼容的问题,增强了系统的灵活性和扩展性。无论是对于初学者还是经验丰富的开发者,理解和掌握变压器模式都是非常有价值的。通过合理运用...
变压器模式是Java设计模式中的一种重要模式,特别适用于解决接口不兼容的问题。通过引入适配器类,可以有效地提高系统的兼容性和灵活性,同时也促进了代码的复用,降低了系统的耦合度。无论是对于初学者还是经验丰富...
《CCM+QR+PSR变压器计算表格》是一款专业用于变压器设计和分析的工具,它集成了连续导电模式(CCM)、准谐振(QR)和部分谐振(PSR)三种工作模式的计算功能,是电气工程领域中不可或缺的实用资源。此压缩包包含一个...
反激式变压器因其独特的工作模式,在低功率应用中被广泛采用,如适配器、充电器等。本文将深入探讨反激式变压器的设计原理、关键参数计算以及设计软件的应用。 首先,理解反激式变压器的基本工作原理至关重要。反激...
反激式变压器是电源转换器设计中的一个重要组成部分,特别是在RCC(Resonant Converter with Current-fed Controller)设计中。RCC电路是一种电流控制型的谐振转换器,它结合了开关电源的优势,如高效率和小体积,...
Java的23种设计模式是软件开发中常用的设计思想,它们可以帮助我们构建更加灵活、可维护和可扩展的代码。以下是对这些模式的详细说明: 1. 工厂模式:这是最基础的创建型设计模式,它提供了一个创建对象的接口,让...
通过研究12V1A电源适配器的电路原理图,我们可以了解电源适配器的工作原理,这对于电子爱好者进行电路设计、故障排查或者 DIY 项目非常有用。同时,这也是学习电子技术、电源设计和电磁兼容性知识的重要途径。
### 连续电流模式反激变压器设计精要 #### 核心知识点概览 1. **反激式变换器(Flyback Converter)的工作原理** - **电路结构**:反激变换器因其简单的电路结构和较低的成本,在小功率电源及电源适配器中广泛...
传统设计方法通常基于DCM模式或临界模式进行计算,但这并不能完全反映反激变压器的实际工作情况。 本文将详细介绍连续电流模式下的反激变压器设计方法,并探讨多路输出次级电流的有效值计算。 #### 二、反激式变换...
反激式变压器是一种在电源转换领域广泛应用的电力电子设备,主要用在电源适配器、充电器等设备中。它的核心在于反激式转换器,也被称为单端反激式或"Buck-Boost"转换器。反激式转换器的工作原理基于电磁能量的存储和...
4. 65WAC-DC笔记本电脑电源适配器,此设计平均能效超过87%,空载输入功率小于100mW,符合能源2之星2.0标准。 5. 60W准谐振电源适配器,它具有谷底锁定功能,防止在轻载条件下的变压器可听噪声,而且平均能效同样...