CodeGym /Blog Java /Ngẫu nhiên /Mẫu thiết kế bộ điều hợp

Mẫu thiết kế bộ điều hợp

Xuất bản trong nhóm
CHÀO! Hôm nay chúng ta sẽ đề cập đến một chủ đề mới quan trọng: các mẫu thiết kế . Những mẫu này là gì? Tôi nghĩ bạn phải biết thành ngữ " không phát minh lại bánh xe ". Trong lập trình, cũng như trong nhiều lĩnh vực khác, có rất nhiều tình huống phổ biến. Khi quá trình phát triển phần mềm đã phát triển, các giải pháp làm sẵn hoạt động đã được tạo ra cho từng giải pháp. Những giải pháp này được gọi là các mẫu thiết kế. Theo quy ước, một mẫu là một số giải pháp được xây dựng như sau: "nếu bạn cần thực hiện X trong chương trình của mình, thì đây là cách tốt nhất để thực hiện". Có rất nhiều mẫu. Cuốn sách xuất sắc "Head First Design Patterns" mà bạn chắc chắn nên làm quen với chúng được dành riêng cho chúng. Mẫu thiết kế bộ điều hợp - 2Nói một cách ngắn gọn, một mẫu bao gồm một vấn đề chung và một giải pháp tương ứng có thể được coi là một loại tiêu chuẩn. Trong bài hôm nay chúng ta sẽ gặp một trong các pattern đó là Adapter. Cái tên của nó đã nói lên tất cả và bạn đã nhiều lần gặp phải những bộ điều hợp trong đời thực. Một số bộ điều hợp phổ biến nhất là đầu đọc thẻ mà nhiều máy tính và máy tính xách tay có. Mẫu thiết kế bộ điều hợp - 3Giả sử chúng ta có một số loại thẻ nhớ. Vậy vấn đề là gì? Nó không biết cách tương tác với máy tính. Họ không chia sẻ một giao diện chung. Máy tính có cổng USB nhưng chúng tôi không thể cắm thẻ nhớ vào đó. Không thể cắm thẻ vào máy tính, vì vậy chúng tôi không thể lưu ảnh, video và các dữ liệu khác. Đầu đọc thẻ là một bộ chuyển đổi giải quyết vấn đề này. Rốt cuộc, nó có cáp USB! Không giống như thẻ, đầu đọc thẻ có thể được cắm vào máy tính. Họ chia sẻ một giao diện chung với máy tính: USB. Hãy xem điều này trông như thế nào trong thực tế:

public interface USB { 

   void connectWithUsbCable(); 
}
Đây là giao diện USB của chúng tôi chỉ với một phương thức kết nối qua USB.

public class MemoryCard { 

   public void insert() { 
       System.out.println("Memory card successfully inserted!"); 
   } 

   public void copyData() { 
       System.out.println("The data has been copied to the computer!"); 
   } 
}
Đây là lớp của chúng tôi đại diện cho thẻ nhớ. Nó đã có 2 phương thức mà chúng ta cần, nhưng đây là vấn đề: Nó không triển khai giao diện USB. Không thể cắm thẻ vào cổng 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(); 
   } 
}
Và đây là bộ chuyển đổi của chúng tôi! những gì làmCardReaderclass làm gì và chính xác thì điều gì làm cho nó trở thành một bộ chuyển đổi? Tất cả đều đơn giản. Lớp được điều chỉnh (Thẻ nhớ) trở thành một trong các trường của bộ điều hợp. Điều này thật ý nghĩa. Khi chúng ta đặt thẻ nhớ bên trong đầu đọc thẻ ngoài đời thực, nó cũng trở thành một phần của nó. Không giống như thẻ nhớ, bộ điều hợp chia sẻ giao diện với máy tính. Nó có cáp USB, tức là nó có thể được kết nối với các thiết bị khác qua USB. Đó là lý do tại sao lớp CardReader của chúng tôi triển khai giao diện USB. Nhưng chính xác những gì xảy ra bên trong phương pháp này? Chính xác những gì chúng ta cần phải xảy ra! Bộ điều hợp ủy thác công việc cho thẻ nhớ của chúng tôi. Thật vậy, bộ điều hợp không tự làm bất cứ điều gì. Đầu đọc thẻ không có bất kỳ chức năng độc lập nào. Công việc của nó chỉ là kết nối máy tính và thẻ nhớ để cho phép thẻ thực hiện công việc của nó - sao chép tệp!connectWithUsbCable()method) để đáp ứng "nhu cầu" của thẻ nhớ. Hãy tạo một số chương trình máy khách sẽ mô phỏng một người muốn sao chép dữ liệu từ thẻ nhớ:

public class Main { 

   public static void main(String[] args) { 

       USB cardReader = new CardReader(new MemoryCard()); 
       cardReader.connectWithUsbCable(); 
   } 
}
Vì vậy, những gì chúng ta đã nhận được? Đầu ra bảng điều khiển:

Memory card successfully inserted! 
The data has been copied to the computer!
Xuất sắc. Chúng tôi đã đạt được mục tiêu của mình! Đây là liên kết đến video có thông tin về mẫu Bộ điều hợp:

Lớp trừu tượng Reader và Writer

Bây giờ chúng ta sẽ quay lại hoạt động yêu thích của mình: tìm hiểu về một vài lớp mới để làm việc với đầu vào và đầu ra :) Tôi tự hỏi chúng ta đã học được bao nhiêu lớp rồi. Hôm nay chúng ta sẽ nói về các Reader và Writercác lớp học. Tại sao cụ thể những lớp học đó? Bởi vì chúng có liên quan đến phần trước của chúng tôi về bộ điều hợp. Hãy xem xét chúng chi tiết hơn. Chúng ta sẽ bắt đầu với  Reader. Readerlà một lớp trừu tượng, vì vậy chúng ta sẽ không thể tạo các đối tượng một cách rõ ràng.   Nhưng bạn thực sự đã quen thuộc với nó! Xét cho cùng, bạn đã quá quen thuộc với các lớp BufferedReaderInputStreamReader, lớp con của nó :)

public class BufferedReader extends Reader { 
… 
} 

public class InputStreamReader extends Reader { 
… 
}
Lớp InputStreamReaderlà một bộ chuyển đổi cổ điển. Như bạn có thể nhớ, chúng ta có thể truyền một InputStreamđối tượng cho hàm tạo của nó. Để làm điều này, chúng ta thường sử dụng System.inbiến:

public static void main(String[] args) { 

   InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
}
Nhưng làm gì InputStreamReader? Giống như mọi bộ điều hợp, nó chuyển đổi giao diện này sang giao diện khác.  Trong trường hợp này, InputStreamgiao diện cho Readergiao diện. Ban đầu, chúng tôi có InputStreamlớp học. Nó hoạt động tốt, nhưng bạn chỉ có thể sử dụng nó để đọc các byte riêng lẻ. Ngoài ra, chúng ta có một Readerlớp trừu tượng. Nó có một số chức năng rất hữu ích — nó biết cách đọc các ký tự! Chúng tôi chắc chắn cần khả năng này. Nhưng ở đây chúng ta phải đối mặt với vấn đề kinh điển thường được giải quyết bằng bộ điều hợp - giao diện không tương thích. Điều đó nghĩa là gì? Chúng ta hãy xem tài liệu của Oracle. Dưới đây là các phương thức của InputStreamlớp. Mẫu thiết kế bộ điều hợp - 4Một tập hợp các phương thức chính xác là giao diện. Như bạn có thể thấy, lớp này có mộtread()(thực tế là một vài biến thể), nhưng nó chỉ có thể đọc byte: byte riêng lẻ hoặc vài byte sử dụng bộ đệm. Nhưng tùy chọn này không phù hợp với chúng tôi — chúng tôi muốn đọc các ký tự. Chúng tôi cần chức năng đã được triển khai trong Readerlớp trừu tượng . Chúng ta cũng có thể thấy điều này trong tài liệu. Mẫu thiết kế bộ điều hợp - 5Tuy nhiên, giao diện InputStreamvà  Readerkhông tương thích! Như bạn có thể thấy, mỗi lần triển khai read()phương thức đều có các tham số và giá trị trả về khác nhau. Và đây là nơi chúng ta cần InputStreamReader! Nó sẽ hoạt động như một bộ điều hợp giữa các lớp của chúng tôi. Như trong ví dụ với đầu đọc thẻ mà chúng ta đã xem xét ở trên, chúng ta đặt một thể hiện của lớp được điều chỉnh "bên trong" lớp bộ điều hợp, tức là chúng ta chuyển một thể hiện tới hàm tạo của nó. Trong ví dụ trước, chúng ta đặt một MemoryCardđối tượng bên trong CardReader. Bây giờ chúng ta đang truyền một InputStream đối tượng cho InputStreamReaderhàm tạo! Chúng tôi sử dụng System.inbiến quen thuộc của mình là InputStream:

public static void main(String[] args) { 

   InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
}
Và thực sự, nhìn vào tài liệu về InputStreamReader, chúng ta có thể thấy rằng việc chuyển thể đã thành công :) Bây giờ chúng ta có các phương pháp để đọc các ký tự theo ý của mình. Mẫu thiết kế bộ điều hợp - 6Và mặc dù System.inđối tượng của chúng tôi (luồng liên kết với bàn phím) ban đầu không cho phép điều này, nhưng những người tạo ngôn ngữ đã giải quyết vấn đề này bằng cách triển khai mẫu bộ điều hợp. Lớp Readertrừu tượng, giống như hầu hết các lớp I/O, có một người anh em sinh đôi —  Writer. Nó có lợi thế lớn giống như  Reader — nó cung cấp một giao diện thuận tiện để làm việc với các ký tự. Với các luồng đầu ra, vấn đề và giải pháp của nó trông giống như với các luồng đầu vào. Có một OutputStreamlớp chỉ có thể ghi byte, có mộtWriterlớp trừu tượng biết cách làm việc với các ký tự và có hai giao diện không tương thích. Vấn đề này một lần nữa được giải quyết bằng mẫu bộ điều hợp. Chúng tôi sử dụng OutputStreamWriterlớp để dễ dàng điều chỉnh hai giao diện của lớp Writer và  OutputStream với nhau. Sau khi chuyển một OutputStreamluồng byte tới hàm tạo, chúng ta có thể sử dụng an OutputStreamWriterđể ghi các ký tự thay vì byte!

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();
   } 
}
Chúng tôi đã viết ký tự có mã 32144 (綐) vào tệp của mình, loại bỏ nhu cầu làm việc với byte :) Đó là nội dung của ngày hôm nay. Hẹn gặp lại các bạn trong các bài học tiếp theo! :)
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION