你好!今天我们将触及一个重要的新话题——模式,或者说——设计模式。什么是模式?我想你知道“不要重新发明轮子”这句话。与许多其他领域一样,编程中也存在大量典型情况。对于他们每个人来说,在编程开发过程中,都创建了现成的工作解决方案。这些是设计模式。相对而言,模式是一个特定的例子,它为以下情况提供了解决方案:“如果你的程序需要做某事,如何最好地做它。” 模式有很多,一本优秀的书《学习设计模式》是专门针对它们的,你绝对应该阅读。 简而言之,模式由一个常见问题及其解决方案组成,这已经可以被认为是一种标准。在今天的讲座中,我们将熟悉其中一种称为“适配器”的模式。它的名字就很能说明问题,您在现实生活中不止一次遇到过适配器。最常见的适配器之一是读卡器,许多计算机和笔记本电脑都配备有读卡器。 想象一下我们有某种存储卡。问题是什么? 事实是她不知道如何与计算机交互。它们没有通用的接口。 计算机具有 USB 接口,但无法将存储卡插入其中。该卡无法插入电脑,因此我们将无法保存我们的照片、视频和其他数据。读卡器就是解决这个问题的适配器。毕竟,它有 USB 电缆!与卡本身不同,读卡器可以插入计算机中。它们与计算机有一个共同的接口——USB。让我们通过一个例子来看看它是什么样子的:
public interface USB {
void connectWithUsbCable();
}
这是我们的USB接口,唯一的方法就是插入USB线:
public class MemoryCard {
public void insert() {
System.out.println("Карта памяти успешно вставлена!");
}
public void copyData() {
System.out.println("Данные скопированы на компьютер!");
}
}
这是我们实现内存映射的类。它已经有我们需要的 2 个方法,但问题是:它没有实现 USB 接口。该卡无法插入 USB 插槽。
public class CardReader implements USB {
private MemoryCard memoryCard;
public CardReader(MemoryCard memoryCard) {
this.memoryCard = memoryCard;
}
@Override
public void connectWithUsbCable() {
this.memoryCard.insert();
this.memoryCard.copyData();
}
}
这是我们的适配器!该类的CardReader
作用是什么?为什么它是一个适配器?这很简单。正在适配的类(内存映射)成为适配器的字段之一。这是符合逻辑的,因为在现实生活中我们也会将卡插入读卡器内部,并且它也成为读卡器的一部分。与存储卡不同,适配器具有与计算机的通用接口。它有一根 USB 电缆,这意味着它可以通过 USB 连接到其他设备。因此,在程序中,我们的类CardReader
实现了USB接口。但是这个方法内部发生了什么?而我们所需要的正是发生了!适配器将工作委托给我们的存储卡。毕竟,适配器本身不做任何事情;读卡器没有任何独立的功能。它的工作只是链接计算机和存储卡,以便卡可以完成其工作并复制文件!我们的适配器通过connectWithUsbCable()
为存储卡的“需求”提供自己的接口(方法)来实现这一点。让我们创建某种客户端程序来模拟想要从存储卡复制数据的人:
public class Main {
public static void main(String[] args) {
USB cardReader = new CardReader(new MemoryCard());
cardReader.connectWithUsbCable();
}
}
结果我们得到了什么?控制台输出:
Карта памяти успешно вставлена!
Данные скопированы на компьютер!
太好了,我们的任务圆满完成了!以下是一些附加链接,其中包含有关适配器模式的信息:
抽象类 Reader 和 Writer
现在我们将回到我们最喜欢的消遣:我们将学习一些用于处理输入和输出的新课程:)我想知道我们已经学了多少?今天我们来谈谈课程Reader
和Writer
。为什么是他们呢?因为这会和我们之前的部分——适配器相关。让我们更详细地看看它们。让我们从Reader
“a”开始。 Reader
是一个抽象类,因此我们无法显式创建它的对象。 但事实上,你已经认识他了!毕竟,您熟悉的类BufferedReader
是InputStreamReader
它的继承人:)
public class BufferedReader extends Reader {
…
}
public class InputStreamReader extends Reader {
…
}
所以,类InputStreamReader
是一个经典的适配器。您可能还记得,我们可以将对象传递给其构造函数InputStream
。大多数情况下,我们使用变量来实现这一点System.in
:
public static void main(String[] args) {
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
它有什么作用InputStreamReader
?与任何适配器一样,它将一种接口转换为另一种接口。在这种情况下,接口InputStream
'a到接口Reader
'a。最初我们有一个班InputStream
。它运行良好,但只能读取单个字节。此外,我们还有一个抽象类Reader
。它具有我们真正需要的出色功能 - 它可以读取字符!当然,我们确实需要这个机会。但这里我们面临着适配器通常解决的一个经典问题——接口不兼容。它是如何体现出来的?让我们直接看一下 Oracle 文档。以下是类方法InputStream
。 一组方法就是一个接口。正如您所看到的,read()
此类有一个方法(即使在多个版本中),但它只能读取字节:单个字节或使用缓冲区的多个字节。这个选项不适合我们——我们想要读取字符。我们需要的功能已经在抽象类中实现了Reader
。这也可以在文档中看到。 然而,InputStream
“a”和Reader
“a”接口不兼容!可以看到,在所有的方法实现中,read()
传递的参数和返回值都是不同的。这就是我们需要它的地方InputStreamReader
!他将充当我们类之间的适配器。正如我们上面看到的读卡器示例一样,我们“在内部”传递“适配”类的对象,即传递给适配器类的构造函数。在前面的示例中,我们MemoryCard
在 内部传递了一个对象CardReader
。现在我们将对象传递InputStream
给构造函数InputStreamReader
!作为一个质量,InputStream
我们使用已经熟悉的变量System.in
:
public static void main(String[] args) {
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
事实上:通过查看文档,InputStreamReader
我们将看到“适应”是成功的:)现在我们拥有了可以读取字符的方法。 尽管最初我们的对象System.in
(绑定到键盘的线程)不允许这样做,但通过创建适配器模式,该语言的创建者解决了这个问题。Reader
与大多数 I/O 类一样,抽象类有一个孪生兄弟 - Writer
。它具有同样大的优点Reader
- 它提供了一个方便的界面来处理符号。对于输出流,问题及其解决方案看起来与输入流的情况相同。有一个类OutputStream
只能写字节;有一个Writer
可以使用符号的抽象类,并且有两个不兼容的接口。这个问题再次被Adapter模式成功解决。使用类,OutputStreamWriter
我们可以轻松地使两个类接口彼此“适应Writer
” OutputStream
。而且,在构造函数中接收到字节流后OutputStream
,在帮助下OutputStreamWriter
我们可以写入字符,而不是字节!
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
OutputStreamWriter streamWriter = new OutputStreamWriter(new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt"));
streamWriter.write(32144);
streamWriter.close();
}
}
我们在文件中写入了一个代码为 32144 - 綐 的字符,从而消除了使用字节的需要:) 今天就这些,我们下节课见!:)
GO TO FULL VERSION