JavaRush /จาวาบล็อก /Random-TH /อะแดปเตอร์รูปแบบการออกแบบ

อะแดปเตอร์รูปแบบการออกแบบ

เผยแพร่ในกลุ่ม
สวัสดี! วันนี้เราจะพูดถึงหัวข้อใหม่ที่สำคัญ - รูปแบบหรืออีกนัยหนึ่ง - รูปแบบการออกแบบ รูปแบบคืออะไร? ฉันคิดว่าคุณคงรู้จักสำนวนที่ว่า “อย่าสร้างวงล้อขึ้นมาใหม่” ในการเขียนโปรแกรม เช่นเดียวกับในด้านอื่นๆ มีสถานการณ์ทั่วไปจำนวนมาก สำหรับแต่ละคนในกระบวนการพัฒนาโปรแกรมจะมีการสร้างโซลูชันการทำงานสำเร็จรูปขึ้นมา เหล่านี้คือรูปแบบการออกแบบ หากจะพูดเชิงเปรียบเทียบ รูปแบบคือตัวอย่างหนึ่งที่นำเสนอวิธีแก้ไขสถานการณ์เช่น “หากโปรแกรมของคุณจำเป็นต้องทำอะไรสักอย่าง จะต้องทำอย่างไรให้ดีที่สุด” มีรูปแบบมากมาย หนังสือดีๆ “การศึกษารูปแบบการออกแบบ” มีไว้สำหรับพวกเขาโดยเฉพาะ ซึ่งคุณควรอ่านอย่างแน่นอน รูปแบบการออกแบบ "อะแดปเตอร์" - 2หากต้องการสรุปให้สั้นที่สุดเท่าที่จะเป็นไปได้ รูปแบบจะประกอบด้วยปัญหาทั่วไปและแนวทางแก้ไข ซึ่งถือได้ว่าเป็นมาตรฐานประเภทหนึ่งอยู่แล้ว ในการบรรยายวันนี้ เราจะมาทำความรู้จักกับรูปแบบหนึ่งที่เรียกว่า "อะแดปเตอร์" ชื่อของมันบ่งบอก และคุณเคยเจออะแดปเตอร์ในชีวิตจริงมากกว่าหนึ่งครั้ง อะแดปเตอร์ที่พบบ่อยที่สุดตัวหนึ่งคือเครื่องอ่านการ์ดซึ่งมีคอมพิวเตอร์และแล็ปท็อปหลายเครื่องติดตั้งอยู่ รูปแบบการออกแบบ "อะแดปเตอร์" - 3ลองนึกภาพว่าเรามีการ์ดหน่วยความจำบางชนิด อะไรคือปัญหา? ความจริงก็คือเธอไม่รู้ว่าจะโต้ตอบกับคอมพิวเตอร์อย่างไร พวกเขาไม่มีอินเทอร์เฟซทั่วไป คอมพิวเตอร์มีขั้วต่อ 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เรียน Паттерн проектирования «Адаптер» - 4ชุดของวิธีการคืออินเทอร์เฟซ อย่างที่คุณเห็นread()คลาสนี้มีเมธอด (แม้จะมีหลายเวอร์ชัน) แต่คลาสนี้สามารถอ่านได้เพียงไบต์เท่านั้น: ไม่ว่าจะเป็นไบต์เดี่ยวหรือหลายไบต์โดยใช้บัฟเฟอร์ ตัวเลือกนี้ไม่เหมาะกับเรา - เราต้องการอ่านตัวอักษร ฟังก์ชั่นที่เราต้องการได้ถูกนำไปใช้แล้วในคลาสนามธรรม Readerสิ่งนี้สามารถเห็นได้ในเอกสารประกอบ Паттерн проектирования «Адаптер» - 5อย่างไรก็ตาม อินเทอร์เฟซ 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เราจะเห็นว่า "การปรับตัว" ประสบความสำเร็จ :) ตอนนี้เรามีวิธีการกำจัดที่ช่วยให้เราสามารถอ่านอักขระได้ Паттерн проектирования «Адаптер» - 6และถึงแม้ว่าในตอนแรกวัตถุของเรา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 - 綐 ลงในไฟล์ของเรา ซึ่งช่วยลดความจำเป็นในการทำงานกับไบต์ :) นั่นคือทั้งหมดสำหรับวันนี้ เจอกันในการบรรยายครั้งต่อไป! :)
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION