views:

202

answers:

5

Hi all,

I want to have a base class, BaseConnect, which contains an OutputStream and children classes ObjectStreamConnect and DataStreamConnect. In my BaseConnect class I have OutputStream os; And in my Two children classes I have the constructors that do "os = ObjectOutputStream(...)" or "os = DataOutputStream(...)", respectively.

Since ObjectOutputStreams have a writeObject(Object o) method and DataOutputStreams do not, it seems that I cannot have my ObjectStreamConnect class do a "os.writeObject(object)" since the parent class, OutputStream, does not have writeObject(Object o).

I'm sure this is code-smelly, and I'm wondering how to handle it.

My thoughts:

I thought of making the method that contains os.writeObject abstract, so that ObjectStreamConnect could implement it differently, but then I realized that DataStreamConnect would also have to implement it, which it does not need to.

I also do not want to just get rid of the parent and have the two classes implement everything separately, because they do have a lot of the same methods with the same implementations.

Please help. For some reason, the answer to this problem is not coming to me.

jbu

edit: I can't paste entire code but it goes something like this:

public class BaseConnect {
  OutputStream os;
   ...
}

public class ObjectStreamConnect extends BaseConnect {
  public ObjectStreamConnect () {
    ...
    os = new ObjectOutputStream(socket.getOutputStream);
  }

  public void writeObject(Object o) {
    os.writeObject(o);
  }
}

public class DataStreamConnect extends BaseConnect {
  public DataStreamConnect () {
    ...
    os = new DataOutputStream(socket.getOutputStream);
  }
}
A: 

Can you just have one abstract method on OutputStream

write(Object o)

(I'm guessing that you can 'write' to both sub-classes) and both subclasses implement it in their own way?

stephendl
The DataStreamConnect class will not have a write(Object o) method because the DataObjectStream class does not have a method for writing objects. Also, not all objects are serializable to be written.
jbu
What does DataObjectStream do then?Also what is the commonality between DataObjectStream and OutputStreamConnect represented in OutputStream? If it isn't the writing part, then you shouldn't be using inheritance via OutputStream for this.
stephendl
+4  A: 

What you seem to be saying is "my two objects use some shared methods, and I'm sharing them through inheritance of a superclass".

Then you get stuck because inheritance actually says "this is one of these, and so has this API" when it isn't - as your difficult-to-implement method suggests.

If you put the shared methods in some sort of helper class, and supply both DataStreamConnect and OutputStreamConnect with an instance of the helper, you can share the support code without having to share the same API.

Dan Vinton
I like this answer.
jbu
+1  A: 

If you are using java 1.5 or above you can us a generic class:

public class Base<T extends OutputStream>{
    T os;
...
}

public class OutputStreamConnect extends Base<ObjectOutputStream>

    public OutputStreamConnet(){
        os = new ObjectOutputStream();
    }

    public void doWrite(Object o){
        os.writeObject(o);
    }
}
Jens Schauder
Will this work? Like I said, DataOutputStreams (child of OutputStream) does not have a writeObject(Object o) method.Maybe I need to research this generic class.
jbu
yes it will work (modulo typos) I used this pattern many times.
Jens Schauder
A: 

You should use an interface to declare the shared vital methods of the two classes. You shouldn't care about future sub-implementation in a base class - it's against the OO-law! Or do you just want a base class so you don't have to write duplicate code? Use an interface and a helper class, as DanVinton suggested.

Björn
A: 

Hi,

If I understand the probleam correctly, you should have the BaseConnect class declared as abstract with the common behavior encapsulated in it. The problematic method writeObject should be declared as abstract as well and you should leave it up to the concrete implementation in a subclass how it manages the desired goal.

Then in the ObjectStreamConnect you can test the type of the stream with instanceof operator, then convert the object to ObjectOutputStream and then you can use the os.writeObject(o) with no probleam.

In the DataStreamConnect you have to implement this method another way.

I mean something like this:

public abstract class BaseConnect {
  protected OutputStream os;
   ...
  public abstract void writeObject(Object o);

  // common behavior implemented in this class
}

public class ObjectStreamConnect extends BaseConnect {
  public ObjectStreamConnect () {
    ...
    os = new ObjectOutputStream(socket.getOutputStream);
  }

  public void writeObject(Object o) {
    if (os instanceof ObjectOutputStream) {
      ((ObjectOutputStream) os).writeObject(o);
    } else {
      // throw some exception here or something, because this should not happen
    }
  }
}

public class DataStreamConnect extends BaseConnect {
  public DataStreamConnect () {
    ...
    os = new DataOutputStream(socket.getOutputStream);
  }

  public void writeObject(Object o) {
    // implement writing of the object in another way here
  }
}

Maybee you should also rename the BaseConnect to AbstractConnect, but this depends on your code conventions.

Martin Lazar