to replace the declared types of declaration elements with ones that have no unneeded members; to minimize coupling between classes
Infer Type can be automatically applied by the Declared Type Generalization Checker, which you might want to try as well.
Infer Type 3 is the latest version of a new Eclipse refactoring that decouples classes by computing for a selected declaration element its maximally general type (interface or abstract class), i.e., that type that contains only the members accessed through the declaration element and the ones it gets assigned to. It then offers the redeclaration of the involved declaration elements with the inferred type (or types, in case this should be necessary).
For users of Eclipses other type refactorings, Infer Type can be described as an automatic version of Extract Interface, combined with Generalize Declared Type and Use Supertype Where Possible. However, Infer Type cannot be replaced by any combination of these.
Infer Type 3 differs from its predecessor (which is part of the Yoxos Eclipse distribution) in the following respects:
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.
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.
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<I> l = new
ArrayList<I>();
public void m() {
I c = l.get(1);
c.m();
}
public void n() {}
}
Infer Type has been automatically applied to all declaration elements of several large code bases.
© The intoJ Team, 2007.