Solved

wierd overriding/inheritance

Posted on 1998-04-29
12
214 Views
Last Modified: 2010-04-16
Hi,

perhaps you can take a look at the code. Figure out what it is going to print.

Somehow, it doesn't print that. And somehow, I have written lots of not-yet-debugged code that expects virtual methods
to behave that way!!!

Basically, this consists of two questions:
a) why does this work this way?
b) what is the safest/best way to fix it?

I cannot provide lots of abstract methods in the Protocol declaration, some protocols don't implement all Request-s
and should default to a method with parameter Request which would print some error message. I don't want to do many
instanceof-s and if-else if-s if at all possible, that seems to be bad design to me. I cannot use specific Protocol-s in Server.

Am I missing something here?

Here's the code:

class WelcomeRequest extends Request {}
class Request {}

abstract class Protocol
{
 public abstract void a( Request r );
}

class SimpleProtocol extends Protocol  
{
 public void a( Request r )
 {
  System.out.println( "sim: unknown request for me - I'm dumb btw" );
 }
}

class AdministrationProtocol extends Protocol
{
 public void a( WelcomeRequest r )
 {
  System.out.println( "adm: welcomerequest - thats fine" );
 }

 public void a( Request r )
 {
  System.out.println( "adm: unknown request for me" );
 }
}

abstract class Server
{
 Protocol p;

 public void s()
 {
  p.a( new WelcomeRequest() );      
 }
}

class AdministrationServer extends Server
{
 public AdministrationServer()
 {
  p = new AdministrationProtocol();
 }
}

class SimpleServer extends Server
{
 public SimpleServer()
 {
  p = new SimpleProtocol();
 }
}

public class Ker
{
 public static void main( String argv[] )
 {
  Server s = new AdministrationServer();
  s.s();
  Server ss = new SimpleServer();
  ss.s();
 }
}
0
Comment
Question by:juris
  • 4
  • 3
  • 2
  • +2
12 Comments
 
LVL 5

Expert Comment

by:msmolyak
ID: 1220187
The way you overload method a in AdministrationServer does not look like a good idea.

The simple solution is

    class AdministrationProtocol extends Protocol
    {
     public void a( Request r )
     {
      if (canHandle(r)
      {
        System.out.println( "adm: welcomerequest - thats fine" );
      }
      else
      {
        System.out.println( "adm: unknown request for me" );
      }
     }

     boolean canHandle(Request r)
     {
       // test whether this request is appropriate for this protocol
     }
    }

Since you Protocol class defines an abstract method which handles any Request (i.e., any of its subclasses), then the AdministrationProtocol should be able to do the same. Thus, you have to sieve requestes coming to the a(Request r) method.

Why a(Request r) and not a(WelcomeRequest r) gets called - this is the question which can be answered for sure after looking at the Java Language Spec (I will try to do it). But whatever the explanation is, you have to live with it.
0
 
LVL 4

Expert Comment

by:evijay
ID: 1220188
Evijay,

I would really appreciate if you would show how to solve this with interfaces.

So far I have thought of:
a) doing lot's of 'instanceof'-s.
b) providing simple methods for each request in the class Protocol.
c) overriding the variable p with the appropriate Protocol descedant
d) something else?

What would be your suggestion?


0
 

Author Comment

by:juris
ID: 1220189
What I mean with c)
is probably providing a getP() abstract method in the Protocol, not sure if it works.

Just overriding a variable will shadow it I guess, won't work.

0
 

Author Comment

by:juris
ID: 1220190
I think msmolyaks answer was very good but obviously not what you had in mind. Here is one elaboration with interfaces. Generally it is good to use interfaces to provide with a common interface to differently implemented classes. The following is one way to do it but might not be good at all depending on how the rest of your stuff is structured and implemented

I would suggest an interface IsRequest that is implemented by Request and WelcomeRequest:

interface IsRequest
{
  public void printMe();
}

class Request implements IsRequest // Quite the same for WelcomeRequest
{
  // You would like to do different things depending on the protocol perhaps?
  // Could take a String as well.
  public void printMeFrom(Protocol p)
  {
    System.out.println( "Something" );
  }
}

abstract class Protocol
{
  // Doesn't need different protocol clases for this aspect anymore.
  // Perhaps you would like to override this one in a subclass to do something
  // different?
  public void a( IsRequest r )
  {
    r.printMeFrom( this );
  }
}
0
 
LVL 1

Expert Comment

by:froderik
ID: 1220191
Uhh,

I guess it would be more logical for my design to make the Data-to-String translation in the Protocol classes, wouldn't it?

Basically I have different Request-s. Each Protocol handles some of them in it's own way.

How does the PrintMeFrom check which protocol was it called from?

0
 

Author Comment

by:juris
ID: 1220192
As I said, it depends...

From an object oriented view, you should place methods that defines a behaviour of a class of objects in that class. Perhaps some part of the printout should be retrieved with a method call to the Request object? Then the a method in Protocol would be something like:
public void a( Request r )
{
  System.out.println( "Print Protocol stuff " + r.someMethod() +
                              " some more Protocol stuff." );
}

The point is to declare useful methods in the IsRequest interface that is common methods for all Requests and then use them instead. Then if you are to add a new Request, you will only have to implement the interface and most of your application will remain unchanged. With different method signatures for different Requests you will have to add a new method for each Request you introduce.

Makes sense or does it sound like nonsense?
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 1

Expert Comment

by:froderik
ID: 1220193
The basic thing is you should apply the Command Design pattern. You have a Receiver (Protocol in this example) which receives Commands (Request in this example) using the a() (Action() method). Since your receiver as well as commands are derived from generic interfaces, on receiving a command, the receiver should be able to decide on what type of request it received (this decision is required for your genericity desired) and take appropriate action.

interface Request {
      public void Execute ();
      public Object getReqInfo();
      public void setReqInfo(Object obj);
}

class WelcomeRequest implements Request {
      Protocol target;
      Object reqInfo;
      public Object getReqInfo() { return reqInfo; }
      public void setReqInfo(Object obj) { reqInfo = obj;}
      public WelcomeRequest (Protocol target)
      {
            this.target = target;
      }
      public void Execute()
      {
            target.a(this);
      }
}
class OrdinaryRequest implements Request {
      Protocol target;
      Object reqInfo;
      public Object getReqInfo() { return reqInfo; }
      public void setReqInfo(Object obj) { reqInfo = obj;}
      public OrdinaryRequest (Protocol target)
      {
            this.target = target;
      }
      public void Execute()
      {
            target.a(this);
      }
}

interface Protocol
{
      public abstract void a(Request r);
}


class SimpleProtocol  implements Protocol
{
      public void a(Request r)
      {
                             if (r instanceof OrdinaryRequest)
                  a((OrdinaryRequest) r);
            else if (r instanceof WelcomeRequest)
                  a((WelcomeRequest) r);
            else
                  System.out.println("SimpleProtocol : received unknown request !!");
      }
      public void a(OrdinaryRequest r)
      {
            System.out.println("SimpleProtocol : received Ordinary request !!");
      }
      public void a(WelcomeRequest r)
      {
            System.out.println("SimpleProtocol : received Welcome request !!");
      }
}

class AdministrationProtocol implements Protocol
{
      public void a(Request r)
      {
            if (r instanceof WelcomeRequest)
                  a((WelcomeRequest) r);
            else
                  System.out.println("AdministrationProtocol : received  unknown request !!");
      }
      public void a(WelcomeRequest r)
      {
            System.out.println("AdministrationProtocol : received Welcome request !!");
      }
}



    abstract class  Server
    {
     Protocol p;

     public void s()
     {
      new WelcomeRequest(p).Execute();
     }
    }

    class AdministrationServer extends Server
    {
     public AdministrationServer()
     {
      p = new AdministrationProtocol();
     }
    }

    class SimpleServer extends Server
    {
     public SimpleServer()
     {
      p = new SimpleProtocol();
     }
    }

    public class Ker1
    {
     public static void main( String argv[] )
     {
      Server s = new AdministrationServer();
      s.s();
      Server ss = new SimpleServer();
      ss.s();
     }
    }       


If you are not still satisfied with this implementation, here is another implementation which avoids the class instanceof decision statements. But you need to put some more effort for this.

interface IRequest {
      public void Execute ();
      public Object getReqInfo();
      public void setReqInfo(Object obj);
}
interface IProtocol
{
      public  void a(IRequest r);
}
interface IWelcomeProtocol extends IProtocol
{
      public void a(WelcomeRequest r);
}
interface IOrdinaryProtocol extends IProtocol{
      public void a(OrdinaryRequest r);
}

class WelcomeRequest implements IRequest {
      IWelcomeProtocol target;
      Object reqInfo;
      public Object getReqInfo() { return reqInfo; }
      public void setReqInfo(Object obj) { reqInfo = obj;}
      public WelcomeRequest (IWelcomeProtocol target)
      {
            this.target = target;
      }
      public void Execute()
      {
            target.a(this);
      }
}
class OrdinaryRequest implements IRequest {
      IOrdinaryProtocol target;
      Object reqInfo;
      public Object getReqInfo() { return reqInfo; }
      public void setReqInfo(Object obj) { reqInfo = obj;}
      public OrdinaryRequest (IOrdinaryProtocol target)
      {
            this.target = target;
      }
      public void Execute()
      {
            target.a(this);
      }
}


class SimpleProtocol  implements IWelcomeProtocol, IOrdinaryProtocol
{
      public void a(IRequest r)
      {
                  System.out.println("SimpleProtocol : received unknown request !!");
      }
      public void a(OrdinaryRequest r)
      {
            System.out.println("SimpleProtocol : received Ordinary request !!");
      }
      public void a(WelcomeRequest r)
      {
            System.out.println("SimpleProtocol : received Welcome request !!");
      }
}

class AdministrationProtocol implements IWelcomeProtocol
{
      public void a(IRequest r)
      {
            System.out.println("AdministrationProtocol : received  unknown request !!");
      }
      public void a(WelcomeRequest r)
      {
            System.out.println("AdministrationProtocol : received Welcome request !!");
      }
}







    abstract class  Server
    {
     IWelcomeProtocol p;
     IOrdinaryProtocol p1;
     public void s()
     {
      new WelcomeRequest(p).Execute();
 
     }
    }

    class AdministrationServer extends Server
    {
     public AdministrationServer()
     {
      p = new AdministrationProtocol();
     }
    }

    class SimpleServer extends Server
    {
     public SimpleServer()
     {
      p = new SimpleProtocol();
     }
    }

    public class Ker1
    {
     public static void main( String argv[] )
     {
      Server s = new AdministrationServer();
      s.s();
      Server ss = new SimpleServer();
      ss.s();
     }
    }       


See, Decide on what exactly you want and then go for a solution.
0
 
LVL 4

Expert Comment

by:evijay
ID: 1220194
The names ICommandProcessor IWelcomeCommandProcessor and IOrdinaryCommandProcessor are more appropriate than the names IProtocol, IWelcomeProtocol and IOrdinaryProtocol
0
 
LVL 4

Expert Comment

by:evijay
ID: 1220195

       15.11.1(url:http://java.sun.com/docs/books/jls/html/15.doc.html#21693 ) you can find several clauses. In that
       your case falls in first case third para i.e.,

       In all other cases, the qualified name has the form FieldName . Identifier; then the name of the method is
       the Identifier and the class or interface to search is  the "declared type" of the field
       named by the FieldName.


       I am stressing the word "declared type" here since this is the word which makes all the difference

       i.e., the class or interface in which the java searches for the method is obtained by declared type of the
       field. i.e.,
       in class Server, the field p has declared type Protocol and not AdministrativeProtocol. So the compiler
       searches for the method a only in class Protocol or its super classes. It finds that only one method is
       having a matching signature ie.,
       public abstract void a(Request r).

       Note that once it finds the signature to be a(Request r) it always sticks to it. it doesnt look for any other
       signature like a(WelcomeRequest r).


       Now, the dynamic binding comes into picture. It tries to look if the method is overridden by a subclass of
       which the variable p is of type. then it invokes the method a(Request r) of the super class and that is the
       reason it printed this way.

       To solve the problem, use interfaces. If you want the exact method, send a comment and i will do it./


Comment
       From: evijay
                                                                              Date: Thursday, April 30 1998 - 10:29AM PDT

       The basic thing is you should apply the Command Design pattern. You have a Receiver (Protocol in this
       example) which receives Commands (Request in this example) using the a() (Action() method). Since your
       receiver as well as commands are derived from generic interfaces, on receiving a command, the receiver should
       be able to decide on what type of request it received (this decision is required for your genericity desired)
       and take appropriate action.

       interface Request {
       public void Execute ();
       public Object getReqInfo();
       public void setReqInfo(Object obj);
       }

       class WelcomeRequest implements Request {
       Protocol target;
       Object reqInfo;
       public Object getReqInfo() { return reqInfo; }
       public void setReqInfo(Object obj) { reqInfo = obj;}
       public WelcomeRequest (Protocol target)
       {
       this.target = target;
       }
       public void Execute()
       {
       target.a(this);
       }
       }
       class OrdinaryRequest implements Request {
       Protocol target;
       Object reqInfo;
       public Object getReqInfo() { return reqInfo; }
       public void setReqInfo(Object obj) { reqInfo = obj;}
       public OrdinaryRequest (Protocol target)
       {
       this.target = target;
       }
       public void Execute()
       {
       target.a(this);
       }
       }

       interface Protocol
       {
       public abstract void a(Request r);
       }


       class SimpleProtocol  implements Protocol
       {
       public void a(Request r)
       {
                                    if (r instanceof OrdinaryRequest)
       a((OrdinaryRequest) r);
       else if (r instanceof WelcomeRequest)
       a((WelcomeRequest) r);
       else
       System.out.println("SimpleProtocol : received unknown request !!");
       }
       public void a(OrdinaryRequest r)
       {
       System.out.println("SimpleProtocol : received Ordinary request !!");
       }
       public void a(WelcomeRequest r)
       {
       System.out.println("SimpleProtocol : received Welcome request !!");
       }
       }

       class AdministrationProtocol implements Protocol
       {
       public void a(Request r)
       {
       if (r instanceof WelcomeRequest)
       a((WelcomeRequest) r);
       else
       System.out.println("AdministrationProtocol : received  unknown request !!");
       }
       public void a(WelcomeRequest r)
       {
       System.out.println("AdministrationProtocol : received Welcome request !!");
       }
       }



           abstract class  Server
           {
            Protocol p;

            public void s()
            {
             new WelcomeRequest(p).Execute();
            }
           }

           class AdministrationServer extends Server
           {
            public AdministrationServer()
            {
             p = new AdministrationProtocol();
            }
           }

           class SimpleServer extends Server
           {
            public SimpleServer()
            {
             p = new SimpleProtocol();
            }
           }

           public class Ker1
           {
            public static void main( String argv[] )
            {
             Server s = new AdministrationServer();
             s.s();
             Server ss = new SimpleServer();
             ss.s();
            }
           }


       If you are not still satisfied with this implementation, here is another implementation which avoids the
       class instanceof decision statements. But you need to put some more effort for this.

       interface IRequest {
       public void Execute ();
       public Object getReqInfo();
       public void setReqInfo(Object obj);
       }
       interface IProtocol
       {
       public  void a(IRequest r);
       }
       interface IWelcomeProtocol extends IProtocol
       {
       public void a(WelcomeRequest r);
       }
       interface IOrdinaryProtocol extends IProtocol{
       public void a(OrdinaryRequest r);
       }

       class WelcomeRequest implements IRequest {
       IWelcomeProtocol target;
       Object reqInfo;
       public Object getReqInfo() { return reqInfo; }
       public void setReqInfo(Object obj) { reqInfo = obj;}
       public WelcomeRequest (IWelcomeProtocol target)
       {
       this.target = target;
       }
       public void Execute()
       {
       target.a(this);
       }
       }
       class OrdinaryRequest implements IRequest {
       IOrdinaryProtocol target;
       Object reqInfo;
       public Object getReqInfo() { return reqInfo; }
       public void setReqInfo(Object obj) { reqInfo = obj;}
       public OrdinaryRequest (IOrdinaryProtocol target)
       {
       this.target = target;
       }
       public void Execute()
       {
       target.a(this);
       }
       }


       class SimpleProtocol  implements IWelcomeProtocol, IOrdinaryProtocol
       {
       public void a(IRequest r)
       {
       System.out.println("SimpleProtocol : received unknown request !!");
       }
       public void a(OrdinaryRequest r)
       {
       System.out.println("SimpleProtocol : received Ordinary request !!");
       }
       public void a(WelcomeRequest r)
       {
       System.out.println("SimpleProtocol : received Welcome request !!");
       }
       }

       class AdministrationProtocol implements IWelcomeProtocol
       {
       public void a(IRequest r)
       {
       System.out.println("AdministrationProtocol : received  unknown request !!");
       }
       public void a(WelcomeRequest r)
       {
       System.out.println("AdministrationProtocol : received Welcome request !!");
       }
       }







           abstract class  Server
           {
            IWelcomeProtocol p;
            IOrdinaryProtocol p1;
            public void s()
            {
             new WelcomeRequest(p).Execute();
         
            }
           }

           class AdministrationServer extends Server
           {
            public AdministrationServer()
            {
             p = new AdministrationProtocol();
            }
           }

           class SimpleServer extends Server
           {
            public SimpleServer()
            {
             p = new SimpleProtocol();
            }
           }

           public class Ker1
           {
            public static void main( String argv[] )
            {
             Server s = new AdministrationServer();
             s.s();
             Server ss = new SimpleServer();
             ss.s();
            }
           }


       See, Decide on what exactly you want and then go for a solution.







                                                          Comment
       From: evijay
                                                                             Date: Thursday, April 30 1998 - 10:32AM PDT

       The names ICommandProcessor IWelcomeCommandProcessor and IOrdinaryCommandProcessor are more appropriate than
       the names IProtocol, IWelcomeProtocol and IOrdinaryProtocol
0
 
LVL 4

Accepted Solution

by:
evijay earned 130 total points
ID: 1220196
Hi juris,
I am answering this inspite of the locked status .

The method definition public abstract void a(Request r) seems to be the trouble maker in this problem. The easiest solution is to declare an abstract function with no parameters say Callme() in the class Protocol. The functionality of them  will be defined in both SimpleProtocol and Administrative Protocol. However if you feel that you will also need the parameters like WecomeRequest etc, then have a function that can store them and that should be used in the Callme function.

The code
public class Ker
{
      public static void main( String argv[] ) throws Exception
      {
            Server s = new AdministrationServer();
            s.s();
            Server ss = new SimpleServer();
            ss.s();
      }
}


class WelcomeRequest extends Request {}
class Request {}

abstract class Protocol
{
      public abstract void a( Request r );
      public abstract void Callme(); // needed.
}

class SimpleProtocol extends Protocol
{
      public void Callme()
      {
            this.a(new WelcomeRequest());
      }
      public void a( Request r )
      {
            System.out.println( "sim: unknown request for me - I'm dumb btw" );
      }
}

class AdministrationProtocol extends Protocol
{
      public void Callme()
      {
            this.a(new WelcomeRequest());
      }

      public void a( WelcomeRequest r )
      {
            System.out.println( "adm: welcomerequest - thats fine" );
      }

      public void a( Request r )
      {
            System.out.println( "adm: unknown request for me" );
      }
}

abstract class Server
{
      Protocol p;

      public void s()
      {
            p.Callme();
      }
}

class AdministrationServer extends Server
{
      public AdministrationServer()
      {
      p = new AdministrationProtocol();
      }
}

class SimpleServer extends Server
{
      public SimpleServer()
      {
      p = new SimpleProtocol();
      }
}  

Reply.
0
 

Expert Comment

by:anandkrish
ID: 1220197
juris,

I was expecting ur reply for the solution i had provided.
0
 

Expert Comment

by:anandkrish
ID: 1220198
Ah, OK, guys, I'm kinda tired of the topic :-)

Thanks a lot!

I guess I'm stuck with doing lot's of 'instanceof'-s.

The behaviour should be in the Protocol classes, not the Request. The Protocols do the translation according to the Request, not the Requests according to the Protocol which is willing to translate them.

Basically thanks a lot, everyone!

anandkrish, I don't think CallMe will help, because there are quite a lot of Requests, not only a WelcomeRequest.

I guess I should have explained how all this works before asking specific questions.

There are protocols - a few (5 or so). There are lot's of request-s which the protocols translate from raw data (Strings) to internal object representations which are then processed and so on. I would like to have as little hassle in adding Requests or handling them as possible. Right now I'm stuck with lot's of else-if-s and instanceof-s.

For example one request is to get the prices for something. In one protocol this would look like:

GET PRICES FOR <item>;

In other

G|PR!

And so on. (this was just an example). Each protocol knows how to translate some of the requests. Also, reverse translation is required.

Oh, what the hell. If anyone has a really nice Design Pattern which is suitable, tell me, if I'll use it I'll give you 139 points once more, I happened to ignore this site for quite some time :-))).

Cheers everyone :-).

0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Suggested Solutions

For customizing the look of your lightweight component and making it look opaque like it was made of plastic.  This tip assumes your component to be of rectangular shape and completely opaque.   (CODE)
For customizing the look of your lightweight component and making it look lucid like it was made of glass. Or: how to make your component more Apple-ish ;) This tip assumes your component to be of rectangular shape and completely opaque. (COD…
The viewer will learn how to implement Singleton Design Pattern in Java.
This video teaches viewers about errors in exception handling.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now