Un-encapsulate refactoring in Eclipse or Intellij? - java

Consider a wrapper class W, wrapping C, this meaning that for most attributes of C, there is a correspondent attribute A on W, its logic consisting in nothing more than delegation to C's A. This situation can be most precisely depicted with the sketch shown below:
class W {
private C c;
getX() { return c.getX(); }
getY() { return c.getY(); }
}
The trouble is that I've decided that I wan't to get rid of getX(), and I'd prefer to either as a transitory step to put C c as public, having all the calling code of W do a w.c.getX() or w.c.getY() or alternatively to put create a W.getC(), and have all calls to getX() and getY() go through it.
What this all boils down is to an "un-encapsulate" refactoring. Is there anything performing this much needed task either in Eclipse or Intellij?

With IntelliJ you can use the Remove Middleman refactoring.
Consider:
Before:
public class W {
private C c;
Object getX() { return c.getX(); }
Object getY() { return c.getY(); }
}
public class C {
private Object x;
private Object y;
public Object getX() {
return x;
}
public Object getY() {
return y;
}
}
public class UsesW {
W w;
public void useW() {
Object x = w.getX();
Object y = w.getY();
}
}
Place your cursor on the declaration of W.c. Then choose Refactor | Remove Middleman.
The result gets you halfway to where you want to be:
After:
public class W {
private C c;
public C getC() {
return c;
}
}
/* class C is unchanged */
public class UsesW {
W w;
public void useW() {
Object x = w.getC().getX();
Object y = w.getC().getY();
}
}
Then you can introduce a variable of type C in UsesW. Place your cursor over one of the calls to w.getC() and inline it: Refactor | Inline... (Ctrl-Alt-N is the default shortcut), choosing to inline all instances. It'll leave you with this:
public class UsesW {
W w;
public void useW() {
final C c = w.getC();
Object x = c.getX();
Object y = c.getY();
}
}
Finally getting rid of W altogether is something you probably can answer better than me, but now that job became significantly easier.

Write your new getC() method.
Rewrite getX() to be return getC().getX().
Inline getX().
The same goes for y.

Related

Visual Studio Code does not allow me to implement my interface(Java)

I have a project with two java files. One is the class withe the main-method and the other is a interface with two methods, which is impelemented in the Java-class and I did override the functions there.
This is my Code from the Java-Class:
public class Point implements Compare {
int y;
int x;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public void setX (int x) {
this.x = x;
}
public void setY (int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public boolean isEqualTo(Point x) {
if ((this.x == x.getX()) && (this.y == x.getY()))
return true;
else
return false;
}
public boolean isSmallerThan(Point x) {
if (this.x < x.getX())
return true;
else if (this.y < x.getY())
return true;
else
return false;
}
public static void main(String[] args) {
System.out.println("Test");
}
}
And this is the Code from my Interface:
public interface Compare {
public boolean isEqualTo();
public boolean isSmallerThan();
}
When I try to run the code i always get the following error:
Point.java:1: error: Point is not abstract and does not override abstract method isSmallerThan() in Compare
public class Point implements Compare {
^
1 error
The strange thing is now, that the same code works when i write it in project in IntelliJ IDEA.
I havent found anything on the internet yet.
ah, and i work on macOS.
Hopefully anybody can help, why the code doesnt work in VSC.
Thanks
Actually, it's not Visual Studio Code. It's a Java compiler.
It tells you "If you declared interface methods and then implementing class with this interface you have to implement them or use abstract class. The method signature should be the same."

JAVA Wildcards Issue with function

Here's the code
class TwoD {
int x, y;
public TwoD(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
class ThreeD extends TwoD {
int z;
public ThreeD(int x, int y, int z) {
super(x, y);
this.z = z;
}
}
class FourD extends ThreeD {
int t;
public FourD(int x, int y, int z, int t) {
super(x, y, z);
this.t = t;
}
}
class coords<T extends TwoD> {
T cordinates;
public coords(T cordinates) {
super();
this.cordinates = cordinates;
}
static void show(coords<? super ThreeD> c) {}
}
public class mainX {
public static void main(String a[]) {
FourD fourD = new FourD(1, 2,3,4);
coords check = new coords(fourD);
coords.show(check);
TwoD twoD = new TwoD(1, 2);
coords check1 = new coords(twoD);
coords.show(check1);
// How this program runs fine with the child and parent subclass objects in show method?
}
}
The method
static void show(coords c)
should only allow Parent class objects ? Why is it allowing child class objects also?
How this program runs fine with the child and parent subhclass objects in show method?
I am confused!
As mentioned by #Thomas in the comments, you're using raw types for your coords. (I could go into detail, but the linked answer explains everything very clearly. Your use case is mainly mentioned in the sections How's a raw type different from using <?> as a type parameter? and A raw type is the erasure of that type.)
If you'd change:
coords check = new coords(fourD);
...
coords check1 = new coords(twoD);
To:
coords<FourD> check = new coords<>(fourD);
...
coords<TwoD> check1 = new coords<>(twoD);
You would get the error you'd expect:
error: incompatible types: coords<TwoD> cannot be converted to coords<? extends ThreeD>
coords.show(check1);
^
PS/off-topic: Class coords should be with a capital C (thus Coords) when following Java's code standards.

How to define multiple acceptable class types for a method parameter?

as a homework assigment, I am asked to build some sort of calculator with java.
In order to make it easier to create expressions, I wanna add constructors that provide "shortcuts" for creating the Num and Var classes. For example, instead of writing new Plus(new Var("x"), new Num(5)) I would like to be able to write new Plus("x", 5) and get the same resulting expression.
in order to not repeat code lines I've created an abstract class called BinaryExpression, inside it are all the possible combination I need for my constructors.
I'm trying to figure out an elegant way to construct a plus class without the need to re-write the same code again.
public abstract class BinaryExpression implements Expression {
protected Expression x;
protected Expression y;
public BinaryExpression(Expression x, Expression y) {
this.x = x;
this.y = y;
}
public BinaryExpression(String x, Expression y) {
this(new Var(x),y);
}
public BinaryExpression(Double x, Expression y) {
this(new Num(x), y);
}
public BinaryExpression(Expression x, String y) {
this(x ,new Var(y));
}
public BinaryExpression(Expression x, Double y) {
this(x ,new Num(y));
}
public BinaryExpression(String x, String y) {
this(new Var(x) ,new Var(y));
}
public BinaryExpression(Double x, Double y) {
this(new Num(x) ,new Num(y));
}
public BinaryExpression(Double x ,String y){
this(new Num(x) ,new Var(y));
}
public BinaryExpression(String x ,Double y){
this(new String(x) ,new Num(y));
}
I searching for a solution like this:
public class Plus extends BinaryExpression {
public Plus(<String,Double, Expression> x, <String,Double, Expression> y) {
super(x, y);
}
so I only accept this class types that way they will fit themselves to their designated constructor inside BinaryExpression class.
thanks :)
The problem is that you need some general container for objects which can be treated as if they were instances of Expression without them actually being instances of Expression. (example: String, Double)
This answer assumes the following:
class Num implements Expression
class Var implements Expression
and that the following constructor exists, or that no constructor is defined for the class Expression
public Expression() {}
I think a good solution would be as #markspace suggested. You can make sure it compiles by using instanceof to determine what to cast the arguments to.
public Plus(Object a, Object b) {
Expression exprA = convertToExpression(a);
Expression exprB = convertToExpression(b);
if(exprA == null || exprB == null) {
// could error handle here or in the place below
}
// do initialization here
}
//
public Expression convertToExpression(Object obj) {
Expression exprObj = null;
if(obj instanceof String) {
exprObj = new Var(obj);
} else if(obj instanceof Double) {
exprObj = new Num(obj);
} else {
// error handle here or in the place above
}
return exprObj;
}
Also, is the last constructor incorrect in your code above?
It seems like it should read like this:
public BinaryExpression(String x, Double y) {
this(new Var(x), new Num(y));
}

How to generically populate an object if the field names are provided?

I need to create and populate an object inside a method. The only information is the member field name (passed as a string) and the relevant value for that field (passed as an Object). What is the most appropriate design pattern taking into account performance? - reflection, if comes with a penalty, would not be a preferred approach.
Update:
The value to be set comes from an object that acts as a generator of the values having a set of methods that return the proper value for the specific field. E.g. for member Double x; it would be generator.getX()
A simple function to copy all the getters to all the available setters is as follows. With some more work you can cache this information and speed it up but it is likely to be fast enough as it is.
public static <T> T copyTo(Object from, T to) {
for(Method m : to.getClass().getMethods()) {
if (!m.getName().startsWith("set") || m.getParameterCount() != 1)
continue;
try {
Method getter = from.getClass().getMethod("g" + m.getName().substring(1));
m.invoke(to, getter.invoke(from));
} catch (NoSuchMethodException ignored) {
// ignored
} catch (InvocationTargetException | IllegalAccessException e) {
throw new AssertionError(e);
}
}
return to;
}
Note: Only the fields where there is a matching getter and setter will attempt to copy from one to the other.
public static void main(String[] args) {
One orig = new One(1, "hi", 3);
One to = new One();
One copy = copyTo(orig, to);
System.out.println(to);
}
static class One {
int x;
String y;
double z;
public One() {
}
public One(int x, String y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
public double getZ() {
return z;
}
public void setZ(double z) {
this.z = z;
}
#Override
public String toString() {
return "One{" +
"x=" + x +
", y='" + y + '\'' +
", z=" + z +
'}';
}
}
prints
One{x=1, y='hi', z=3.0}
If you want to create an object generically you need to use reflection.
The only alternative is byte code generation which will be much more complex to implement and only save you a fraction of a micro-second.
How many days is it worth sending to implement this to save a micro-second?
If you know the class name of the object then what you can do is:
public Object populate(String className,String fieldName,Object value) throws Exception{
Class clazz = Class.forName(className);
Object o = null;
for(Field f: clazz.getFields()){
if(f.getName().equals(fieldName)){
o = clazz.getConstructor().newInstance();//default constructor if it exists
f.set(o, value);
break;
}
}
return o;
}
EDIT:
Since you know the class(comment under question) then you can use is the function I wrote just with this change and not className parameter:
Class clazz = Class.forName(YourClass.class.getName());
EDIT2:
If I understand the update you are asking about how to know which method to invoke to get the value.
On your generator class you can get the list of methods it has. Then if your method are named getFieldName() you can once you have the field name find the method with the name getFiledName.
Example:
for(Method m:GeneratorClass.class.getMethods()){
System.out.println(m.getName());
//analyze method name and field name to determine which method to call
//..
boolean callThis = true;//result of analysis
if(callThis){
//Object value = m.invoke(obj);
//obj==generator
}
}

The class that implements the interface doesn't work because "Class is not abstract and does not override abstract method...". What is the mistake?

There is an example of "Implementing an Interface" in Java tutorial. I have repeated this example but it doesn't work. NetBeans shows the mistake on te left of RectanglePlus class declaration. And mistake is:
rectangleplus.RectanglePlus is not abstract and does not override
abstract method isLargerThan(rectangleplus.Relatable) in
rectangleplus.Relatable
I did the same as written in tutorial. Why it shows the mistake? Here is my implementation of the project.
The name of the project is RectanglePlus.
The name of the package is rectangleplus.
1st file in the project is Interface Relatable:
package rectangleplus;
public interface Relatable {
int isLarger(Relatable other);
}
2nd file in the project is Main Class RectanglePlus with helper class Point:
package rectangleplus;
public class RectanglePlus implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
// four constructors
public RectanglePlus() {
origin = new Point(0, 0);
}
public RectanglePlus(Point p) {
origin = p;
}
public RectanglePlus(int w, int h) {
origin = new Point(0, 0);
width = w;
height = h;
}
public RectanglePlus(Point p, int w, int h) {
origin = p;
width = w;
height = h;
}
// a method for moving the rectangle
public void move(int x, int y) {
origin.x = x;
origin.y = y;
}
// a method for computing
// the area of the rectangle
public int getArea() {
return width * height;
}
// a method required to implement
// the Relatable interface
public int isLargerThan(Relatable other) {
RectanglePlus otherRect
= (RectanglePlus)other;
if (this.getArea() < otherRect.getArea())
return -1;
else if (this.getArea() > otherRect.getArea())
return 1;
else
return 0;
}
public static void main(String[] args) {
// TODO code application logic here
}
}
class Point {
int top;
int left;
int x;
int y;
public Point(int t, int l) {
top = t;
left = l;
}
}
Why there is nothing said about abstraction in the tutorial example? Should the tutorial example work without mitakes?
Thank you.
In the interface, you declare the method isLarger but in the class you declare isLargerThan Change one to the other name and it will go fine.
You're not correctly implementing the isLarger() method in the Relatable interface. Rename the isLargerThan(Relatable other) method so it looks like this:
#Override
int isLarger(Relatable other) {
}
It's a good idea to use the #Override annotation, it allows you to catch errors like the one in the question.

Categories