Използването на слоеве от обекти за динамично и прозрачно добавяне на отговорности към дадени обекти се нарича декораторски шаблон. (Шаблоните1 са тема на глава 16.) Декораторският шяблон определя, че всички обекти които обвиват вашия ще имат един и същ интерфейс, за да се направи използването на декораторите прозрачно – едно и също съобщение се изпраща към обекта, независимо дали е декориран или не е. Това е основанието за съществуване на “филтърните” класове в IO библиотеката на Java: абстрактният “филтърен” е базов клас за всички декоратори. (Един декоратор трябва да има същия интерфейс като обекта който декорира, но декораторът също може и да разшири интерфейса, което и става в някои от “филтърните” класове).
Декораторите често се употребяват когато е необходимо да се поддържат всички необходими комбинации от подкласове – толкова мнага на брой, че субкласингът е непрактичен. IO библиотеката на Java изисква много комбинации на различни черти, което прави декораторският подход практичен. Има обаче и недостатък с декораторския шаблон. Декораторите дамат много гъвкавост когато пишете програмата (понеже може лесно да смесвате и нагласявате атрибути), но се добавя сложност на кода ви. Причината IO библиотеката на Java да е тромава при използване е че трябва да създадете много класове –“чистия” IO тип плюс всичките декоратори – за да може да се сдобиете с единствения IO обект който ви трябва.
Класовете които дават декораторския интерфейс към конкретен InputStream или OutputStream са FilterInputStream и FilterOutputStream – които нямат много интуитивни имена. Те са извлечени, респективно, от InputStream и OutputStream, абстрактни класове са, на теория да дават общ интерфейс на всичките начини, по които искате да говорите на потока. На практика FilterInputStream и FilterOutputStream просто подражават на базовите си класове, което е ключово изискване за един декоратор.
Четене от InputStream
с FilterInputStream
Класовете FilterInputStream правят две много различни неща. DataInputStream подволява да се четат различни примитивни типове данни както и String обекти. (Всички методи започват с “read,” както readByte( ), readFloat( ) и т.н.) Така, заедно със съпътстващия ги DataOutputStream, позволява да се преместват данни от едно място на друго посредством поток. Тези “места” се определят от класовете в Таблица 10-1. Ако четете данните на блокове и ги разделяте сами, не се нуждаете от DataInputStream, но в повечето други случаи ще го използвате за форматиране на данните при четене.
Останалите класове променят начина на вътрешното поведение на InputStream: дали да е буфериран или не, да следи ли прочетените линии (позволявайки ви да го питате за номер на ред и да задавате номер на ред) и дали може да се слага един знак обратно в потока. Последните два класа много приличат на такива за поддържане на компилатор (тоест, те са били добавине за постройката на Java компилатор), така че вероятно няма да ги използвате в общото програмиране.
Вероятно ще искате буфер почти винаги, независимо с какво IO устройство сте се скачили, така че по-смислено щеше да бъде специалният случай в IO библиотеката да бъде небуферирания вход, а не буферирания.
Таблица 10-3. Типове FilterInputStream
-
Клас
|
Функция
|
Аргументи на конструктора
|
Как да се използва
|
Data-InputStream
|
Използван заедно с DataOutputStream, така че може да четете примитиви (int, char, long, и т.н.) от поток по преносим начин.
|
InputStream
|
Съдържа пълен интерфейс за четене на примитиви.
|
-
Buffered-InputStream
|
Използвайте го за предотвратяване на физическото четене всеки път когато трябват още данни. Казвате “Използвай буфер.”
|
InputStream, с дължина на буфера по желание.
|
Не дава интерфейс per se, само изискването да се използва буфер. Присъединете интерфейсен обект.
|
LineNumber-InputStream
|
Следи числата във входния поток; може да извикате getLineNumber( ) и setLineNumber(int).
|
InputStream
|
Просто добавя номера на линии, така че вероятно ще присъедините интерфейсен обект.
|
Pushback-InputStream
|
Има еднобайтов буфер така че може да бутнете обратно прочетен знак.
|
InputStream
|
Изобщо се използва като скенер за компилатор и вероятно е включен заради Java компилатора. Вероятно няма да го използвате.
| Писане в OutputStream
с FilterOutputStream
Допълнителен към DataInputStream е DataOutputStream, който форматира всеки от римитивните типове и String обекти в поток по такъв начин, че DataInputStream, на каквато и да е машина, може да ги чете. Всичките методи започват с “write,” както writeByte( ), writeFloat( ) и т.н.
Ако искате да направите истински форматирано извеждане, например към конзолата, използвайте PrintStream. Това е крайната точка която позволява да се извеждат всички примитивни типове и String обекти във видим формат като противоположност на DataOutputStream, чиято цел е да се сложат в поток така, че DataInputStream преносимо да може да ги реконструира. Статичният обект System.out е PrintStream.
Двата важни метода в PrintStream са print( ) и println( ), които са претоварени да извеждат всички примитивни типове. Разликата между print( ) и println( ) е че последният добавя край на ред когато се изпълни.
BufferedOutputStream е модификатор и въвежда използването на буфер, така че да не е нужно физическо писане при всяко писане в поток. Вероятно винаги ще искате да го използвате с файлове, а възможно е и с конзолен IO.
Таблица 10-4. Типове FilterOutputStream
-
Клас
|
Функция
|
Аргументи на конструктора
|
Как да се използва
|
Data-OutputStream
|
Заедно с DataInputStream така че може да пишете примитиви (int, char, long, и т.н.) в поток по преносим начин.
|
OutputStream
|
Съдържа пълен интерфейс да позволи писането на всички примитивни типове.
|
PrintStream
|
За форматилар изход. Докато DataOutputStream е за запомняне на данни, PrintStream е за изобразяване.
|
OutputStream, с булева ктойност по желание, която индицира дали бужерът ще се изпразва след всеки нов ред.
|
Трябва да бъде “final” обгръщащ вашия OutputStream обект. Вероятно ще го използвате много.
|
Buffered-OutputStream
|
Използвайте го за избягване на физическото писане при добавяне на всяко късче данни. Казвате “Използвай буфер.” Може да използвате flush( ) за запис и изпразване на буфера.
|
OutputStream, с дължина на буфер по желание.
|
Не дава интерфейс per se, само определя използването на буфер. Присъединете интерфейсен обект.
|
Сподели с приятели: |