two Java classes that share many of their methods but dont have a "is a" relationship

Viewed 446

i am implementing two classes that share many methods but i cant make one inherit from the other as it doesn't make sense so i opted for a shared interface with all the shared methods. but i realized that many methods have the same implementation for both classes too so my question would be how can i make these methods "inherit" from a default method kind of like "super" methods in inheritance?

one solution that im thinking of is creating a parent class so that both my classes can inherit from it

4 Answers

Inheritance should be used when you need to refer to a common ancestor, not to 'share' common code. You say that the two objects do not have this relationship but do have common code - the obvious approach is to factor that out into it's own class (or interface or whatever) and compose into your objects:

You didn't provide an example so I'll make one up:

class CommonStuff {
    // common members here
}

class One {
    private final CommonStuff common;
}

class Two {
    private final CommonStuff common;
}

No need for inheritance and its inherent hard coupling (pun intended).

Yes Abstract Class is the right approach for this if you have some default implementation for methods otherwise you can go for interface.

Write all your common piece of logic in your Abstract class methods and make these methods abstract if you want the subclass to override the implementation otherwise you don't need to make them abstract methods

To expand on my comment: you want to use composition as well as the decorator pattern with delegation

For example:

public interface Foo {
    public void a();
    public void b();
    
}
// used as the inner class
public class ConcreteFoo implements Foo {
    public void a() {
        // implementation for a
    }
    
    public void b() {
        // implementation for b
    }
}
public class MyContainerA implements Foo {
    private Foo innerFoo;
    
    public MyContainerA(Foo innerFoo) {
        this.innerFoo = innerFoo;
    }
    
    public void a() {
        // delegate the method call to the contained object
        innerFoo.a();
    }
    
    public void b() {
        // delegate
        innerFoo.b();
    }
    
    public void methodOnlyInContainerA() {
        
    }
}
public class MyContainerB implements Foo {
    private Foo innerFoo;
    
    public MyContainerB(Foo innerFoo) {
        this.innerFoo = innerFoo;
    }
    
    public void a() {
        innerFoo.a();
    }
    
    public void b() {
        innerFoo.b();
    }
    
    public void methodOnlyInContainerB() {
        
    }

}    

elsewhere:

Foo foo = new ConcreteFoo();

// both guys below use the same inner class
MyContainerA contA = new MyContainerA(foo);
MyContainerB contB = new MyContainerB(foo);

you can create an abstract class that has the methods which have the same implementation in your subclasses you do not repeat yourself DRY like so: enter image description here

an implementation can look something like so :

abstract class Shape  
 { 
String color; 
  
// these are abstract methods 
abstract double area(); 
public abstract String toString(); 
  
// abstract class can have constructor 
public Shape(String color) { 
    System.out.println("Shape constructor called"); 
    this.color = color; 
} 
  
// this is a concrete method 
public String getColor() { 
    return color; 
} 
} 
class Circle extends Shape 
{ 
double radius; 
  
public Circle(String color,double radius) { 

    // calling Shape constructor 
    super(color); 
    System.out.println("Circle constructor called"); 
    this.radius = radius; 
} 

@Override
double area() { 
    return Math.PI * Math.pow(radius, 2); 
} 

@Override
public String toString() { 
    return "Circle color is " + super.color +  
                   "and area is : " + area(); 
} 
  
   } 
  class Rectangle extends Shape{ 

double length; 
double width; 
  
public Rectangle(String color,double length,double width) { 
    // calling Shape constructor 
    super(color); 
    System.out.println("Rectangle constructor called"); 
    this.length = length; 
    this.width = width; 
} 
  
@Override
double area() { 
    return length*width; 
} 

@Override
public String toString() { 
    return "Rectangle color is " + super.color +  
                       "and area is : " + area(); 
} 

  } 
public class Test  
 { 
public static void main(String[] args) 
{ 
    Shape s1 = new Circle("Red", 2.2); 
    Shape s2 = new Rectangle("Yellow", 2, 4); 
      
    System.out.println(s1.toString()); 
    System.out.println(s2.toString()); 
} 
  } 

Output:

  Shape constructor called
  Circle constructor called
  Shape constructor called
   Rectangle constructor called
   Circle color is Redand area is : 15.205308443374602
  Rectangle color is Yellowand area is : 8.0

Advantages of Abstraction

It reduces the complexity of viewing things. Avoids code duplication and increases reusability. Helps to increase the security of an application or program as only important details are provided to the user.

I hope this will help you in your case

Related