สวัสดี! วันนี้เราจะพูดถึงหัวข้อใหม่ที่สำคัญ - รูปแบบหรืออีกนัยหนึ่ง - รูปแบบการออกแบบ รูปแบบคืออะไร? ฉันคิดว่าคุณคงรู้จักสำนวนที่ว่า “อย่าสร้างวงล้อขึ้นมาใหม่” ในการเขียนโปรแกรม เช่นเดียวกับในด้านอื่นๆ มีสถานการณ์ทั่วไปจำนวนมาก สำหรับแต่ละคนในกระบวนการพัฒนาโปรแกรมจะมีการสร้างโซลูชันการทำงานสำเร็จรูปขึ้นมา เหล่านี้คือรูปแบบการออกแบบ หากจะพูดเชิงเปรียบเทียบ รูปแบบคือตัวอย่างหนึ่งที่นำเสนอวิธีแก้ไขสถานการณ์เช่น “หากโปรแกรมของคุณจำเป็นต้องทำอะไรสักอย่าง จะต้องทำอย่างไรให้ดีที่สุด” มีรูปแบบมากมาย หนังสือดีๆ “การศึกษารูปแบบการออกแบบ” มีไว้สำหรับพวกเขาโดยเฉพาะ ซึ่งคุณควรอ่านอย่างแน่นอน หากต้องการสรุปให้สั้นที่สุดเท่าที่จะเป็นไปได้ รูปแบบจะประกอบด้วยปัญหาทั่วไปและแนวทางแก้ไข ซึ่งถือได้ว่าเป็นมาตรฐานประเภทหนึ่งอยู่แล้ว ในการบรรยายวันนี้ เราจะมาทำความรู้จักกับรูปแบบหนึ่งที่เรียกว่า "อะแดปเตอร์" ชื่อของมันบ่งบอก และคุณเคยเจออะแดปเตอร์ในชีวิตจริงมากกว่าหนึ่งครั้ง อะแดปเตอร์ที่พบบ่อยที่สุดตัวหนึ่งคือเครื่องอ่านการ์ดซึ่งมีคอมพิวเตอร์และแล็ปท็อปหลายเครื่องติดตั้งอยู่ ลองนึกภาพว่าเรามีการ์ดหน่วยความจำบางชนิด อะไรคือปัญหา? ความจริงก็คือเธอไม่รู้ว่าจะโต้ตอบกับคอมพิวเตอร์อย่างไร พวกเขาไม่มีอินเทอร์เฟซทั่วไป คอมพิวเตอร์มีขั้วต่อ 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
! เขาจะทำหน้าที่เป็นอะแดปเตอร์ระหว่างชั้นเรียนของเรา ดังตัวอย่างในเครื่องอ่านการ์ดที่เราดูข้างต้น เราจะส่งอ็อบเจ็กต์ของคลาส "adapted" "ภายใน" ไปยังตัวสร้างของคลาสอะแดปเตอร์ ในตัวอย่างก่อนหน้านี้ เราได้ส่งวัตถุเข้าไป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
ที่สามารถทำงานกับสัญลักษณ์ได้ และมีอินเทอร์เฟซที่เข้ากันไม่ได้สองรายการ ปัญหานี้ได้รับการแก้ไขอีกครั้งด้วยรูปแบบอะแดปเตอร์ การใช้คลาสทำให้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