Infer Type:Examples

From Intoj.org

Revision as of 14:38, 27 July 2007 by Phil (Talk | contribs)
(diff) ←Older revision | Current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search

[edit] Decoupling clients from servers

A client class referencing a server class is coupled to that server class through the reference. If the server offers more than the client needs, this couplig is unnecessarily strong in that the server cannot be replaced by others not offering the unneeded members. For instance, in the code

 public class Client {
     Server s;
     public Client(Server s) {
           s.m();
           this.s = s;
     }
     void n() {
           s.n();
     }
 }

class Client references class Server twice, through its field s and through the formal parameter of its constructor. Depending on what else the server offers in his public interface, this coupling can be reduced by replacing references to Server with an inferred type. Executing Infer Type on field s produces

  public interface IServer {
   void n();
 }

 public class Server implements IServer {...}

 public class Client {
     IServer s;
     public Client(Server s) {
           s.m();
           this.s = s;
     }
     void n() {
           s.n();
     }
 }

executing it on the parameter of the constructor produces

 public interface IServer {
   void n();
   void m();
 }
 
 public class Server implements IServer {...}
 
 public class Client {
     IServer s;
     public Client(IServer s) {
           s.m();
           this.s = s;
     }
     void n() {
           s.n();
     }
}

To make sure that all references of a class to another are replaced with a single new type in a single refactoring, Infer Type must be executed on the corresponding import statement.

[edit] Computing the required interface of a class

Given the code

package exp;

public class D {
     public void m() {}
     public void n() {}
     public void o() {}
}

package imp;

import exp.D;

public class C {
     D d;
     D e;
     void m() {d.m(); e.n();}
}

executing Infer Type on the import of D in C will compute and insert a new supertype of D containing only m() and n(). Likewise, in the example of Client and Server above, executing Infer Type on the import of Server in Client will replace all occurrences of Server in Client with one new inferred type, independently of any particular declaration element.

[edit] Generalizing type arguments

The Infer Generic Type Arguments refactoring of Eclipse can derive the most specific type parameter for a declaration using a raw type. Conversely, Infer Type can compute the maximally general type parameter for that declaration. For instance, given the code

public class C {
     List<C> l = new ArrayList<C>();
     public void m() {
           C c = l.get(1);
           c.m();
     }
     public void n() {}
}

executing Infer Type on the type argument C computes a new abstract supertype for C containing only m(), and replaces the type parameter C with it:

public interface I {
   void m();
} 
public class C implements I {
     List l = new ArrayList<I>();
     public void m() {
           I c = l.get(1);
           c.m();
     }
     public void n() {}
}