Another design for your critque - abstract method

E

Edward A Thompson

I have an abstract class with an abstract method. When I extend the
class, 4 times out of 4I want to pass the method a String, but 1time
out of 4 I want to pass it another class:

So what I did was define someParam as an Object, and end up with the
following:

abstract class A {
....
abstract calc (Object someParam) {};
....
}

public class A1 extends A {
...
public calc (Object a) { String x = a.toString(); };
...
}

public class A4 extends A {
....
public class calc (Object b) { MyClass m = (MyClass)b; };
....
}

Is this good/bad design? Is it standard? Is there a better way to
accomplish this?

Seems to me this allows something other than String or MyClass to be
passed without the compiler's knowledge.

I appreciate any feedback.
 
A

Anton Spaans

You see this quite a bit (with, for example the equals() method).

I would suggest to add one overloaded method to A4:

public class A4 extends A {
....
public class calc (Object b) { MyClass m = (MyClass)b; }; // or {
calc((MyClass)b); }
public class calc (MyClass b) { MyClass m = b; };
....
}

This will enable the compiler to bind calls to the method calc(MyClass) and
no runtime class-cast is necessary.
the method calc(Object) must still be there to satisfy the abstract
baseclass.

-- Anton.
 
D

Dimitri Maziuk

Anton Spaans sez:
You see this quite a bit (with, for example the equals() method).

I would suggest to add one overloaded method to A4:

public class A4 extends A {
...
public class calc (Object b) { MyClass m = (MyClass)b; }; // or {
calc((MyClass)b); }
public class calc (MyClass b) { MyClass m = b; };
...
}

This will enable the compiler to bind calls to the method calc(MyClass) and
no runtime class-cast is necessary.
the method calc(Object) must still be there to satisfy the abstract
baseclass.

Are you sure you want to use Object.toString() here? If a is a String,
you're making a copy. If it isn't, you'll still get a valid string but
it probably won't be what you expect.

I'd make it { String x = (String) a; } (actually, I'd use instanceof)
and then, following Anton's logic, add another overloaded method to
base class. One that takes String as parameter.

And then I'd ask myself why have abstract method that takes an
Object, and what's the point of having that abstract class at all.

Dima
 
C

Christophe Vanfleteren

Dimitri said:
Are you sure you want to use Object.toString() here? If a is a String,
you're making a copy. If it isn't, you'll still get a valid string but
it probably won't be what you expect.

Just a minor nitpick here:

you're not making a copy if the variable a is a String.
The toString() method in String is implemented like this:

/**
* This object (which is already a string!) is itself returned.
*
* @return the string itself.
*/
public String toString() {
return this;
}
 
E

Ed Thompson

And then I'd ask myself why have abstract method that takes an
Object, and what's the point of having that abstract class at all.

Why have any abstract class? To force the subclass to implement a class
of that name/type?
 
A

Adam

Ed Thompson said:
Why have any abstract class? To force the subclass to implement a class
of that name/type?

Yes, but your abstract class seems too abstract.
Having
abstract class MyClass
{
abstract void myMethod(Object o);
}
is considered to be bad design.

Other people gave you a tip to use overloaded abstract methods:
abstract class MyClass
{
abstract void myMethod(Type1 o);
abstract void myMethod(Type2 o);
abstract void myMethod(Type3 o);
}
and this is much better.
But if your concrete classes just need *one*
of those overloaded methods,
you end up with something like:
class MyConcreteClass extends MyClass
{
void myMethod(Type1 o)
{
System.out.println("Yes! MyConcreteClass expected Type1 as a
parameter!");
}
void myMethod(Type2 o){ throw new Error("MyConcreteClass does not
want or expect Type2!!!"); }
void myMethod(Type3 o){ throw new Error("MyConcreteClass does not
want or expect Type3!!!"); }
}

Which still is not perfect.

Knowing that little about your problem I can't help much,
but I think you could make some use of double dispatching
(or Visitor pattern) in some form of it.

Adam
 
H

Hans Granqvist

Anton Spaans said:
...
This will enable the compiler to bind calls to the method calc(MyClass) and
no runtime class-cast is necessary.
the method calc(Object) must still be there to satisfy the abstract
baseclass.
...

This is quite nice indeed. Excellent.


Also, I'd add an instanceof check and throw IllegalArgumentException,
but only if there is also some sort of 'supports()' call:

abstract class Base {
abstract void f(Object o) throws IllegalArgumentException;
abstract boolean supports(Object o);
}


class Derived extends Base {
void f(Object o) throws IllegalArgumentException{
if (!(o instanceof String)){
throw new IllegalArgumentException(...);
}
g((String) o);
}

void g(String s){
...;
}

boolean supports(Object o){
return o instanceof String;
}
}


The idea being that you should always be able to prevent
exceptions if possible.

-Hans
 
E

Edward A Thompson

Also, I'd add an instanceof check and throw IllegalArgumentException,
but only if there is also some sort of 'supports()' call:

abstract class Base {
abstract void f(Object o) throws IllegalArgumentException;
abstract boolean supports(Object o);
}


class Derived extends Base {
void f(Object o) throws IllegalArgumentException{
if (!(o instanceof String)){
throw new IllegalArgumentException(...);
}
g((String) o);
}

void g(String s){
...;
}

boolean supports(Object o){
return o instanceof String;
}
}

I don't see your use of supports here?
 

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

Staff online

Members online

Forum statistics

Threads
473,767
Messages
2,569,571
Members
45,045
Latest member
DRCM

Latest Threads

Top