CodeGym /Java блог /Случаен /Шаблон за проектиране на адаптер
John Squirrels
Ниво
San Francisco

Шаблон за проектиране на адаптер

Публикувано в групата
здрасти Днес ще се докоснем до една важна нова тема: дизайнерски модели . Какви са тези модели? Мисля, че трябва да знаете израза „ не преоткривайте колелото “. В програмирането, Howто и в много други области, има голям брой често срещани ситуации. С развитието на софтуерната разработка за всеки от тях са създадени готови работещи решения. Тези решения се наричат ​​шаблони за проектиране. По конвенция моделът е няHowво решение, формулирано така: "ако трябва да направите X във вашата програма, тогава това е най-добрият начин да го направите". Има много модели. На тях е посветена страхотната книга "Head First Design Patterns", с която определено трябва да се запознаете. Шаблон за проектиране на адаптер - 2Казано накратко, моделът се състои от общ проблем и съответно решение, което може да се счита за вид стандарт. В днешния урок ще се запознаем с един от тези модели: Адаптер. Името му казва всичко и вие сте срещали адаптери много пъти в реалния живот. Някои от най-често срещаните адаптери са четците на карти, които имат много компютри и лаптопи. Шаблон за проектиране на адаптер - 3Да предположим, че имаме няHowва карта с памет. Та Howъв е проблема? То не знае How да взаимодейства с компютъра. Те не споделят общ интерфейс. Компютърът има USB порт, но не можем да поставим картата с памет в него. Картата не може да бъде включена в компютъра, така че не можем да запазим нашите снимки, видеоклипове и други данни. Четецът на карти е адаптер, който решава този проблем. Все пак има USB кабел! За разлика от самата карта, четецът на карти може да бъде включен в компютъра. Те споделят общ интерфейс с компютъра: USB. Нека да видим How изглежда това на практика:

public interface USB { 

   void connectWithUsbCable(); 
}
Това е нашият USB интерфейс само с един метод за свързване през 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!"); 
   } 
}
Това е нашият клас, представляващ картата с памет. Той вече има 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(); 
   } 
}
И ето го нашия адаптер! Какво правиCardReaderclass do и Howво точно го прави адаптер? Всичко е просто. Класът, който се адаптира (MemoryCard), става едно от полетата на адаптера. Това има смисъл. Когато поставим карта с памет в четец на карти в реалния живот, тя също става част от него. За разлика от картата с памет, адаптерът споделя интерфейс с компютъра. Има USB кабел, тоест може да се свързва с други устройства чрез USB. Ето защо нашият клас CardReader имплементира USB интерфейса. Но Howво точно се случва вътре в този метод? Точно това, което трябва да се случи! Адаптерът делегира работата на нашата карта с памет. Всъщност адаптерът не прави нищо сам. Четецът на карти няма независима функционалност. Неговата задача е само да свърже компютъра и картата с памет, за да може картата да си върши работата — копиране на файлове!connectWithUsbCable()метод), за да отговори на „нуждите“ на картата с памет. Нека създадем клиентска програма, която ще симулира човек, който иска да копира данни от карта с памет:

public class Main { 

   public static void main(String[] args) { 

       USB cardReader = new CardReader(new MemoryCard()); 
       cardReader.connectWithUsbCable(); 
   } 
}
И така, Howво получихме? Конзолен изход:

Memory card successfully inserted! 
The data has been copied to the computer!
Отлично. Постигнахме целта си! Ето връзка към видеоклип с информация за модела на адаптера:

Абстрактни класове по читател и писател

Сега ще се върнем към любимата ни дейност: запознаване с няколко нови класа за работа с вход и изход :) Чудя се колко вече сме научor. Днес ще говорим за Reader и Writerкласове. Защо точно тези класове? Тъй като те са свързани с предишния ни раздел за адаптери. Нека ги разгледаме по-подробно. Ще започнем с  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); 
}
Но Howво InputStreamReaderправи? Като всеки адаптер, той преобразува един интерфейс в друг.  В този случай интерфейсът InputStreamкъм Readerинтерфейса. Първоначално имаме InputStreamкласа. Работи добре, но можете да го използвате само за четене на отделни byteове. Освен това имаме Readerабстрактен клас. Има някои много полезни функции — знае How да чете знаци! Със сигурност имаме нужда от тази способност. Но тук се сблъскваме с класическия проблем, който обикновено се решава от адаптери - несъвместими интерфейси. Какво означава това? Нека да разгледаме documentацията на Oracle. Ето методите на InputStreamкласа. Шаблон за проектиране на адаптер - 4Набор от методи е точно това, което е интерфейс. Както можете да видите, този клас има aread()метод (всъщност няколко варианта), но може да чете само byteове: or отделни byteове, or няколко byteа с помощта на буфер. Но тази опция не ни подхожда - искаме да четем знаци. Имаме нужда от функционалността, която вече е внедрена в Readerабстрактния клас . Можем да видим това и в documentацията. Интерфейсите и  Шаблон за проектиране на адаптер - 5обаче са несъвместими! Както можете да видите, всяка реализация на метода има различни параметри и връщани стойности. И това е мястото, от което имаме нужда ! Той ще действа като адаптер между нашите класове. InputStreamReaderread()InputStreamReaderКакто в примера с четеца на карти, който разгледахме по-горе, поставяме екземпляр на адаптирания клас "вътре" в класа на адаптера, т.е. предаваме такъв на неговия конструктор. В предишния пример поставихме MemoryCardобект вътре CardReader. Сега предаваме InputStream обект на InputStreamReaderконструктора! Използваме нашата позната System.inпроменлива като InputStream:

public static void main(String[] args) { 

   InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
}
И наистина, разглеждайки documentацията за InputStreamReader, можем да видим, че адаптацията е успешна :) Сега имаме методи за четене на знаци на наше разположение. Шаблон за проектиране на адаптер - 6И въпреки че нашият System.inобект (потокът, свързан с клавиатурата) първоначално не позволяваше това, създателите на езика решиха този проблем чрез прилагане на модела на адаптера. Абстрактният Readerклас, подобно на повечето I/O класове, има брат близнак —  Writer. Има същото голямо предимство като  Reader — осигурява удобен интерфейс за работа с герои. При изходните потоци проблемът и неговото решение изглеждат по същия начин като при входните потоци. Има OutputStreamклас, който може да записва само byteове, имаWriterабстрактен клас, който знае How да работи със знаци и има два несъвместими интерфейса. Този проблем отново се решава от модела на адаптера. Използваме OutputStreamWriterкласа, за да адаптираме лесно двата интерфейса на класовете Writer и  OutputStream един към друг. След предаване на OutputStreamпоток от byteове към конструктора, можем да използваме OutputStreamWriterза запис на символи, а не на 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();
   } 
}
Написахме символа с code 32144 (綐) в нашия файл, елиминирайки необходимостта от работа с byteове :) Това е всичко за днес. Ще се видим в следващите уроци! :)
Коментари
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION