Results 1 to 5 of 5
  1. #1
    Greatwolf is offline Member
    Join Date
    Jul 2010
    Posts
    2
    Rep Power
    0

    Question How is Java inheritance being used to enforce program requirements?

    I was looking at a blog about good API design here

    In one of the example sections titled 'Reinventing the Socket', it showed a design of how to enforce certain rules and prerequisite on the client code that uses it. eg. the client must call bind() before it can call connect(), and it must be connected before it's allowed to send() or receive() data.

    I'm more familiar with C/C++ so I'm having some trouble fully comprehending how the class design is enforcing the API rules. Like for example, how do you prevent client code from making calls into this API with something like this:

    Java Code:
    SocketConnected s = socket.bind(localaddress, 1000);
    
    //client doesn't call the connect() method
    //and just calls the send() method right away.
    
    //this line should give compile-time error
    //because only bind() was called but not connect()
    s.send(/* some data goes here */);
    How and why would the compiler catch that error? If I'm understanding the subclass inheritance correctly, SocketConnected is-a SocketBound which is-a Socket. But if the client code is able to declare a SocketConnected object, how can you enforce the rule that bind() and connect() must be called before send() and receive() are allowed?

    I get what most of the code is doing but the part that confuses me is near the bottom where the author says:

    Java Code:
    s.bind(localAddr, 1000); 
    s.connect(remoteAddr, 70);
    How could that type of usage be equivalent to

    Java Code:
    SocketConnected s = socket.bind(localAddr, 1000).connect(remoteAddr, 70)
    ?

    Also is there a design pattern that generalizes this example?

    Thank

  2. #2
    Zack's Avatar
    Zack is offline Senior Member
    Join Date
    Jun 2010
    Location
    Destiny Islands
    Posts
    692
    Rep Power
    5

    Default

    First, I think I'll mention that calling send() without both bind() and connect() would result in a runtime error rather than a compile-time error. (The blog author also mentions this: "Any attempt to perform these operations out of order will result in a runtime error.") Basically, the reason this happens is that the Socket object has some way of detecting whether or not it's connected; if it's not, then it will not perform the send() actions. Basically this:
    Java Code:
    public void send(String data) {
    	if (this.connected == false) { return; }
    	// Some code to send data.
    }


    Second, note that in his interfaces, his return values are Sockets also. So when he talks about this code:
    Java Code:
    SocketConnected s = socket.bind(localAddr, 1000).connect(remoteAddr, 70)
    It's equivalent to the first code because the bind() has returned a Socket object.

    I'll explain that a bit further:

    Let's imagine you have some class A, which has two class variables:
    Java Code:
    public class A {
    	int var1;
    	boolean var2;
    
    	public void SetV1(int val) {
    		this.var1 = val;
    	}
    	public void SetV2(boolean val) {
    		this.var2 = val;
    	}
    }
    You will notice that the return types are void; therefore they're not returning anything. So something like this would be invalid:
    Java Code:
    (new A()).SetV1(5).SetV2(true);
    Now imagine that class A is now this:
    Java Code:
    public class A {
    	int var1;
    	boolean var2;
    
    	public A SetV1(int val) {
    		this.var1 = val;
    		return this;
    	}
    	public A SetV2(boolean val) {
    		this.var2 = val;
    		return this;
    	}
    }
    Now, instead of returning void, it returns an "A" object. This allows us to "chain" the commands together, because each function returns an A object:
    Java Code:
    A Something = new A();
    Something.SetV1(5);
    Something.SetV2(true);
    Java Code:
    A Something = new A();
    Something.SetV1(5).SetV2(true);
    Java Code:
    A Something = (new A()).SetV1(5).SetV2(true);
    All of the above are equivalent.


    Now I hope I've answered your question... if not you'll have to be a little more specific about the information you're after.

    Best of luck!
    Last edited by Zack; 07-22-2010 at 06:11 AM. Reason: Added code example for first half.

  3. #3
    Tolls is offline Moderator
    Join Date
    Apr 2009
    Posts
    11,755
    Rep Power
    19

    Default

    Actually, the author is stating that the current Socket implementation will result in a runtime error. His proposal would result in a compile time error.

    This is all about coding to interfaces. He suggests a Socket interface that simply allows you to bind(). You would get this Socket object, presumably, from some form of Factory, so you would never actually create one yourself using new.

    The concrete class of this object is irrelevant to you when you code, but I would imagine it would actually implement all 3 interfaces, and simply return itself on the bind() and connet().

    But the point is that with this mechanism you cannot connect() before you have run bind(), and you cannot transmit() before you have connect()ed. The compiler will throw an error. Thus you can (help) prevent misuse.

    ETA: Just to clarify. The Socket interface provides access to the SocketBound interface which then provides access to the SocketConnected interface. You cannot get access to a SocketBound or a SocketConnected without successfully running a method from one of the earlier interfaces.

  4. #4
    Greatwolf is offline Member
    Join Date
    Jul 2010
    Posts
    2
    Rep Power
    0

    Thumbs up

    Thank you for the response and clarification everyone.

    Ok, in other words, under the new redesigned socket interfaces, the following usage in client code is valid then:

    Java Code:
    //assuming CreateSocketFactory() instantiates a concrete socket object
    Socket socket = CreateSocketFactory();
    
    //the way this was demo in author's example code
    SocketConnected s = socket.bind(localAddr, 1000).connect(remoteAddr, 70);
    or client code could also use it like so:


    Java Code:
    Socket socket = CreateSocketFactory();
    
    //lengthier way to do the same thing
    SocketBound sockbound = socket.bind(localAddr, 1000);
    SocketConnected s = sockbound.connect(remoteAddr, 70);
    and finally the code snippet below was how the client would use the original socket API but under the new redesigned API it would generate a compile error:

    Java Code:
    s.bind(localAddr, 1000); 
    s.connect(remoteAddr, 70);

  5. #5
    Tolls is offline Moderator
    Join Date
    Apr 2009
    Posts
    11,755
    Rep Power
    19

    Default

    That's pretty much it.
    In the original you could do bind() then connect() (on the same Socket object).
    In the proposed setup you couldn't actually do that because no interface has both those methods...well, short of casting the Socket to an possible ConcreteSocketClass which has all the interfaces. ;)

Similar Threads

  1. different requirements on the same server
    By ra78 in forum Networking
    Replies: 12
    Last Post: 06-28-2010, 05:50 PM
  2. Requirements for building a SSL VPN
    By adityag in forum New To Java
    Replies: 0
    Last Post: 01-19-2010, 04:46 PM
  3. New to Java.. What are the requirements?
    By konn in forum New To Java
    Replies: 10
    Last Post: 03-27-2009, 12:50 PM
  4. External DTD requirements
    By jwilley44 in forum XML
    Replies: 0
    Last Post: 03-06-2009, 09:25 PM
  5. Inheritance Program
    By Schaput in forum New To Java
    Replies: 6
    Last Post: 11-14-2008, 12:42 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •