On class design

J

jakash3

I've noticed that in Languages like Java and C#, some classes have
methods named "GetInputStream" and "GetOutputStream" rather than
having the class inherit from a stream class. For example. Instead of
having something like this:

Code:
File f;
f.open("foo.txt");
f.print("hello world!\n");
f.print("aslkdfj sladkfj sladkf");
f.close();
(where File inherits from both InputStream and OutputStream)

You have something like this:

Code:
File f;
OutputStream os;
os = f.GetOutputStream();
os.print("hello world!\n");
os.print("asdfj sladkfj sladkf");
f.close();

Which design is better?
 
G

Goran

I've noticed that in Languages like Java and C#, some classes have
methods named "GetInputStream" and "GetOutputStream" rather than
having the class inherit from a stream class. For example. Instead of
having something like this:

Code:
File f;
f.open("foo.txt");
f.print("hello world!\n");
f.print("aslkdfj sladkfj sladkf");
f.close();
(where File inherits from both InputStream and OutputStream)

You have something like this:

Code:
File f;
OutputStream os;
os = f.GetOutputStream();
os.print("hello world!\n");
os.print("asdfj sladkfj sladkf");
f.close();

Which design is better?

First is clearly better if a "File" class is sufficient for all
"streaming"^^^ needs you'll ever have. Second is better if your
streams aren't always files (e.g. you want to "save" something by
sending it to another server over the network, and indeed, you can
find file-like objects that talk to an FTP server, or if you merely
want to "save" it without any disk operation (e.g. a memory stream).
Also, separate stream helps if you want specific features on top of
what streaming through a file offers. For example, having a buffered
stream helps in speeding up file operations, and having a
"compressing" stream (the one that turns "raw" stream into a
compressed form, say, by gzip-ing the data) helps in taking less space
or bandwidth.

Streaming: not watching porn over internet ;-), but rather, turning
data from arbitrary structure into a byte-after-byte stream of bytes
(for the purpose of reverting that into original data at a later
stage).

Goran.
 
T

Tobias Müller

jakash3 said:
I've noticed that in Languages like Java and C#, some classes have
methods named "GetInputStream" and "GetOutputStream" rather than
having the class inherit from a stream class. For example. Instead of
having something like this:

Code:
File f;
f.open("foo.txt");
f.print("hello world!\n");
f.print("aslkdfj sladkfj sladkf");
f.close();
(where File inherits from both InputStream and OutputStream)

You have something like this:

Code:
File f;
OutputStream os;
os = f.GetOutputStream();
os.print("hello world!\n");
os.print("asdfj sladkfj sladkf");
f.close();

Which design is better?

In the case of a File class I would strongly prefer the second variant,
because a File class is usually used for moving, copying, deleting, or
testing for existence of a file. That means, the actual file does not have
to be open or even existent to construct a File object.
However, to use stream functionality, you need an existing file, you need
the correct permissions and you must open it correctly.
The GetXxxStream() method provides you a clearly defined point where the
file is opened and a single point of failure in the case that you can't.
And by closing the stream you can unlock the actual file and use again the
File methods for example to delete it.

So use the second variant always if the class does not represent a stream
by itself, but some other resource that can be used to acquire a stream by
e.g. opening a file, establishing a connection, or something similar.

Tobi
 
J

Jorgen Grahn

.
Code:
File f;
OutputStream os;
os = f.GetOutputStream();
os.print("hello world!\n");
os.print("asdfj sladkfj sladkf");
f.close();

Which design is better?

In the case of a File class I would strongly prefer the second variant,
because a File class is usually used for moving, copying, deleting, or
testing for existence of a file. That means, the actual file does not have
to be open or even existent to construct a File object.
However, to use stream functionality, you need an existing file, you need
the correct permissions and you must open it correctly.
The GetXxxStream() method provides you a clearly defined point where the
file is opened and a single point of failure in the case that you can't.

Then I'd prefer to call it Open(). GetXxxStream() makes it sound as
something that cannot fail (as if the opening took place a long time
ago and you're just picking up a reference to the result).

/Jorgen
 
T

Tobias Müller

Jorgen Grahn said:
Then I'd prefer to call it Open(). GetXxxStream() makes it sound as
something that cannot fail (as if the opening took place a long time
ago and you're just picking up a reference to the result).

/Jorgen

True. But the concept of separating the functionality is still better IMO.
It's better to enforce correct programs by the type system rather than just
document the correct call sequence (Not to call print() before open() for
example)

Anyway, it would be interesting to see a concrete example with such a
GetXxxStream() method (from the Java API or similar) rather than just
speculate.

Tobi
 
J

jakash3

I think I should make a stream class and 2 derived line stream and
buffer stream classes. None of those classes will be abstract, instead
the core putc and getc methods will just fail with a ENOTSUP error
instead of being pure virtual. Specialized derived classes like
Filestream and Socketstream and Memoerystream will have to overload
them so that it will work. So then I should have something like this:

Code:
Linestream *lns;
Stream *s;
socket::tcp sock;

sock.connect("www.google.com", "80");
lns = sock.getstream();
s = sock.getstream();
lns->puts("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n");
con.put(s->read(1, atoi(lns->drink("\r\n\r\n").slurp("Content-Length:
"))));
sock.close();
delete lns;
delete s;

where sock.getstream will return a new socketstream object which can
be assigned to one of the stream, linestream, or bufstream pointers
for polymorphism.
lns.drink("\r\n\r\n") means read data from socket as string until a \r
\n\r\n sequence is detected. and the .slurp("Content-Length: ") means
remove "Content-Length: " from this string and all character preceding
it. con.put means write this object to the console screen. Stream
s.read(size_t size, size_t nmemb) means read nmemb elements each of
size byte long from this stream and return it as a data object.

The project relating to this that I'm working on is this:
http://sourceforge.net/projects/libaxcel/
 
J

Jorgen Grahn

True. But the concept of separating the functionality is still better IMO.
It's better to enforce correct programs by the type system rather than just
document the correct call sequence (Not to call print() before open() for
example)

No conflict there -- I imagined a

std::eek:stream& Foo::eek:pen();

method.
Anyway, it would be interesting to see a concrete example with such a
GetXxxStream() method (from the Java API or similar) rather than just
speculate.

Yes -- the OP seemed to be heavily based in Java and C#, but I know
nothing about the background in that world for his question.

/Jorgen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top