こんにちは!今日は、重要な新しいトピックであるパターン、つまりデザインパターンについて触れます。パターンとは何ですか? 「車輪の再発明をしない」という言葉をご存知かと思います。他の多くの分野と同様、プログラミングにも典型的な状況が多数あります。それぞれについて、プログラミング開発の過程で、既製の実用的なソリューションが作成されました。これらはデザインパターンです。比較的言えば、パターンとは、「プログラムで何かを行う必要がある場合、それを行う最善の方法」のような状況に対する解決策を提供する特定の例です。パターンはたくさんありますが、それらについて解説した優れた本「デザインパターンの学習」が掲載されているので、ぜひ読んでください。 できるだけ簡単に言うと、パターンは共通の問題とその解決策で構成されており、すでに一種の標準と考えることができます。今日の講義では、これらのパターンの 1 つである「アダプター」について学びます。その名前はそれを物語っていて、あなたは現実の生活の中で何度もアダプターに遭遇したことがあります。最も一般的なアダプタの 1 つはカード リーダーで、多くのコンピュータやラップトップに搭載されています。 ある種のメモリカードがあると想像してください。何が問題ですか? 実際のところ、彼女はコンピュータと対話する方法を知りません。これらには共通のインターフェイスがありません。 パソコンには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
何をするものですか?なぜアダプターなのでしょうか? それは簡単です。適応されるクラス (メモリ マップ) は、アダプターのフィールドの 1 つになります。実生活ではカードリーダーにカードを挿入し、それもカードリーダーの一部になるため、これは論理的です。メモリ カードとは異なり、アダプタにはコンピュータとの共通のインターフェイスがあります。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
。なぜ彼らについて?これは前のセクションであるアダプターに関連するためです。それらをさらに詳しく見てみましょう。「a」から始めましょうReader
。 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
!彼はクラス間のアダプターとして機能します。上で見たカード リーダーの例と同様に、「adapted」クラスのオブジェクトを「内部的に」、つまりアダプター クラスのコンストラクターに渡します。MemoryCard
前の例では、の中にオブジェクトを渡しましたCardReader
。次に、オブジェクトをInputStream
コンストラクターに渡しますInputStreamReader
。特性として、InputStream
すでにおなじみの変数を使用しますSystem.in
。
public static void main(String[] args) {
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
そして実際: ドキュメントを見ると、InputStreamReader
「適応」が成功したことがわかります :) これで、文字を読み取ることができるメソッドが自由に使えるようになりました。 そして、当初私たちのオブジェクトSystem.in
(キーボードにバインドされたスレッド) ではこれが許可されていませんでしたが、Adapterパターンを作成することで、言語の作成者はこの問題を解決しました。抽象クラス はReader
、ほとんどの I/O クラスと同様に、双子の兄弟 - を持っていますWriter
。これにも同じ大きな利点がありますReader
。シンボルを操作するための便利なインターフェイスが提供されます。出力ストリームの場合、問題とその解決策は入力ストリームの場合と同じように見えます。OutputStream
バイトしか書き込めないクラスがあります。Writer
シンボルを操作できる抽象クラスがあり、互換性のないインターフェイスが 2 つあります。この問題も、アダプター パターンによって正常に解決されます。クラスを使用すると、OutputStreamWriter
2 つのクラス インターフェイスを相互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