Adding attributes and useful interfaces | CodeGuru

Adding attributes and useful interfaces

Bruce Eckel’s Thinking in Java Contents | Prev | Next and useful interfaces The use of layered objects to dynamically and transparently add responsibilities to individual objects is referred to as the decorator pattern. (Patterns [47] are the subject of Chapter 16.) The decorator pattern specifies that all objects that wrap around your initial object […]

Written By
CodeGuru Staff
CodeGuru Staff
Mar 1, 2001
5 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

and
useful interfaces

The


use of layered objects to dynamically and transparently add responsibilities to


individual objects is referred to as the

decorator
pattern. (Patterns
[47]
are the subject of Chapter 16.) The decorator pattern specifies that all
objects that wrap around your initial object have the same interface, to make
the use of the decorators transparent – you send the same message to an
object whether it’s been decorated or not. This is the reason for the
existence of the “filter” classes in the Java IO library: the
abstract “filter” class is the base class for all the decorators.
(A decorator must have the same interface as the object it decorates, but the
decorator can also extend the interface, which occurs in several of the
“filter” classes).

Decorators


are often used when subclassing requires a large number of subclasses to


support every possible combination needed – so many that subclassing


becomes impractical. The Java IO library requires many different combinations


of features which is why the decorator pattern is a good approach. There is a


drawback to the decorator pattern, however. Decorators give you much more


flexibility while you’re writing a program (since you can easily mix and


match attributes), but they add complexity to your code. The reason that the


Java IO library is awkward to use is that you must create many classes –


the “core” IO type plus all the decorators – in order to get


the single IO object that you want.

The


classes that provide the decorator interface to control a particular


InputStream

or


OutputStream

are the


FilterInputStream

and


FilterOutputStream

– which don’t have very intuitive names. They are derived,


respectively, from


InputStream

and


OutputStream

,


and they are abstract classes, in theory to provide a common interface for all


the different ways you want to talk to a stream. In fact,


FilterInputStream

and


FilterOutputStream

simply mimic their base classes, which is the key requirement of the decorator.


Reading
from an InputStream

with
FilterInputStream

The


FilterInputStream

classes accomplish two significantly different things.


DataInputStream

allows you to read different types of primitive data as well as


String

objects. (All the methods start with “read,” such as


readByte( )

,


readFloat( )

,


etc.) This, along with its companion


DataOutputStream

,


allows you to move primitive data from one place to another via a stream. These


“places” are determined by the classes in Table 10-1. If


you’re reading data in blocks and parsing it yourself, you won’t


need


DataInputStream

,


but in most other cases you will want to use it to automatically format the


data you read.

The


remaining classes modify the way an


InputStream

behaves internally: whether it’s buffered or unbuffered, if it keeps


track of the lines it’s reading (allowing you to ask for line numbers or


set the line number), and whether you can push back a single character. The


last two classes look a lot like support for building a compiler (that is, they


were added to support the construction of the Java compiler), so you probably


won’t use them in general programming.

You’ll


probably need to buffer your input almost every time, regardless of the IO


device you’re connecting to, so it would have made more sense for the IO


library to make a special case for unbuffered input rather than buffered input.

Table
10-3. Types of FilterInputStream

Class Function Constructor
Arguments
How
to use it
Data-InputStream Used
in concert with
DataOutputStream,
so you can read primitives (int, char, long, etc.) from a stream in a portable
fashion.
InputStream
Contains
a full interface to allow you to read primitive types.

Buffered-InputStream Use
this to prevent a physical read every time you want more data. You’re
saying “Use a buffer.”
InputStream,
with optional buffer size.
This
doesn’t provide an interface
per
se
,
just a requirement that a buffer be used. Attach an interface object.
LineNumber-InputStream Keeps
track of line numbers in the input stream; you can call
getLineNumber( )
and
setLineNumber(int).
InputStream
This
just adds line numbering, so you’ll probably attach an interface object.
Pushback-InputStream Has
a one byte push-back buffer so that you can push back the last character read.
InputStream
Generally
used in the scanner for a compiler and probably included because the Java
compiler needed it. You probably won’t use this.

Writing
to an OutputStream

with
FilterOutputStream

The


complement to


DataInputStream

is


DataOutputStream

,


which formats each of the primitive types and


String

objects onto a stream in such a way that any


DataInputStream

,


on any machine, can read them. All the methods start with “write,”


such as


writeByte( )

,


writeFloat( )

,


etc.

If


you want to do true formatted output, for example, to the console, use a


PrintStream

.


This is the endpoint that allows you to print all of the primitive data types


and


String

objects in a viewable format as opposed to


DataOutputStream,

whose goal is to put them on a stream in a way that


DataInputStream

can portably reconstruct them. The


System.out

static object is a


PrintStream

.

The


two important methods in


PrintStream

are


print( )

and


println( )

,


which are overloaded to print out all the various types. The difference between


print( )

and


println( )

is that the latter adds a newline when it’s done.

BufferedOutputStream

is a modifier and tells the stream to use buffering so you don’t get a


physical write every time you write to the stream. You’ll probably always


want to use this with files, and possibly console IO.

Table
10-4. Types of FilterOutputStream
Class Function Constructor
Arguments How
to use it

Data-OutputStream Used
in concert with
DataInputStream
so you can write primitives (int, char, long, etc.) to a stream in a portable
fashion.
OutputStream
Contains
full interface to allow you to write primitive types.
PrintStream For
producing formatted output. While
DataOutputStream
handles the
storage
of data,
PrintStream
handles
display.
OutputStream,
with optional boolean indicating that the buffer is flushed with every newline.
Should
be the “final” wrapping for your
OutputStream
object. You’ll probably use this a lot.
Buffered-OutputStream Use
this to prevent a physical write every time you send a piece of data.
You’re saying “Use a buffer.” You can call
flush( )
to flush the buffer.
OutputStream,
with optional buffer size.
This
doesn’t provide an interface
per
se
,
just a requirement that a buffer is used. Attach an interface object.

[47]

In


Design
Patterns

,


Erich Gamma


et
al.

,


Addison-Wesley 1995. Described later in this book.

Contents

|

Prev

|

Next
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.