The Polymorphism Way
The implementation above has several drawbacks. What if we wanted to do some other operations on the user's given shapes? We would have to do that operation on each object in each case
block. What if you had hundreds of different shapes? You would need to update hundreds of blocks just to add a similar-looking line! We would also need more ArrayLists
to hold the results.
Polymorphism to the rescue! Let's re-implement this program using the concept of polymorphism. We know that all rectangles, circles, and squares are a type of Shape, so we can declare all of these as shapes and use a common rule for them. We will do the following things in our code:
- Create a shapeClasses array where all the blueprints (class references like Rectangle, Square, etc.) will be kept.
- When a user gives inputs to create an ith shape, we will automatically create an instance of that class from the shapeClasses array.
- Note that we create the (i-1)th shape according to the user input
i
since arrays are 0 indexed.
- Note that we create the (i-1)th shape according to the user input
xxxxxxxxxx
34
}
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Enter number of shapes to calculate : ");
int n = sc.nextInt();
// Create a list of classes
ArrayList<Class> shapeClasses = new ArrayList<>();
// Popular with our 3 shapes
shapeClasses.add(Rectangle.class); shapeClasses.add(Square.class); shapeClasses.add(Circle.class);
// A list of user created shapes
ArrayList<Shape> shapes = new ArrayList<>();
for (int i = 0; i < n; i++) {
System.out.print("Enter the shape type\n1) Rectangle\n2) Square\n3) Circle\nInput : ");
int select = sc.nextInt();
// Input validation
if(select > 3 || select < 1) {
System.out.print("Please Enter a valid Value"); i--; continue;
}
try {
Shape shape = (Shape) shapeClasses.get(select-1).getDeclaredConstructor().newInstance();
shape.inputFromUser();
shapes.add(shape);
} catch (Exception e) {
e.printStackTrace();
}
}
// Now we calculate the average from the shapes list
Double average = shapes.stream().mapToDouble(val -> val.getArea()).average().orElse(0.0);
OUTPUT
:001 > Cmd/Ctrl-Enter to run, Cmd/Ctrl-/ to comment
javascript
xxxxxxxxxx
24
class Main {
constructor() {
this.shapeClasses = [Rectangle, Square, Circle];
this.shapes = [];
}
shapesCalculation(n) {
for (let i = 0; i < n; i++) {
let select = prompt("Enter the shape type\n1) Rectangle\n2) Square\n3) Circle\nInput : ");
if(select > 3 || select < 1) {
console.log("Please Enter a valid Value");
i--;
continue;
}
let shape = new this.shapeClasses[select-1]();
shape.inputFromUser();
this.shapes.push(shape);
}
let total = this.shapes.reduce((sum, shape) => sum + shape.getArea(), 0);
let average = total / this.shapes.length;
console.log("The average of all shapes' area is : " + average);
}
}
OUTPUT
:001 > Cmd/Ctrl-Enter to run, Cmd/Ctrl-/ to comment
python
xxxxxxxxxx
18
class Main:
def __init__(self):
self.shapeClasses = [Rectangle, Square, Circle]
self.shapes = []
def shapesCalculation(self, n):
for i in range(n):
select = int(input("Enter the shape type\n1) Rectangle\n2) Square\n3) Circle\nInput : "))
if select > 3 or select < 1:
print("Please Enter a valid value")
continue
shape = self.shapeClasses[select-1]()
shape.inputFromUser()
self.shapes.append(shape)
total = sum(shape.getArea() for shape in self.shapes)
average = total / len(self.shapes) if self.shapes else 0
print(f"The average of all shapes' area is : {average}")
OUTPUT
:001 > Cmd/Ctrl-Enter to run, Cmd/Ctrl-/ to comment
cpp
xxxxxxxxxx
26
class Main {
public:
vector<Shape*> shapes;
vector<Shape*> shapeClasses = {new Rectangle(), new Square(), new Circle()};
void shapesCalculation(int n) {
for (int i = 0; i < n; i++) {
cout << "Enter the shape type\n1) Rectangle\n2) Square\n3) Circle\nInput : ";
int select;
cin >> select;
if(select > 3 || select < 1) {
cout << "Please enter a valid value";
continue;
}
shapes.push_back(shapeClasses[select-1]);
shapes.back()->inputFromUser();
}
double total = 0.0;
for (Shape* shape : shapes) {
total += shape->getArea();
}
double average = (shapes.size() ? total/shapes.size() : 0);
cout << "The average of all shapes' area is : " << average << endl;
}
};
OUTPUT
:001 > Cmd/Ctrl-Enter to run, Cmd/Ctrl-/ to comment
csharp
xxxxxxxxxx
25
class MainClass {
ArrayList shapeClasses = new ArrayList() { typeof(Rectangle), typeof(Square), typeof(Circle) };
ArrayList shapes = new ArrayList();
public void ShapesCalculation(int n) {
for (int i = 0; i < n; i++) {
Console.WriteLine("Enter the shape type\n1) Rectangle\n2) Square\n3) Circle\nInput : ");
int select = Convert.ToInt32(Console.ReadLine());
if (select > 3 || select < 1) {
Console.WriteLine("Please Enter a valid value");
continue;
}
var shape = (Shape)Activator.CreateInstance((Type)shapeClasses[select-1]);
shape.InputFromUser();
shapes.Add(shape);
}
double total = 0;
foreach (Shape shape in shapes) {
total += shape.GetArea();
}
double average = (shapes.Count > 0 ? total/shapes.Count : 0);
Console.WriteLine("The average of all shapes' area is : " + average);
}
}
OUTPUT
:001 > Cmd/Ctrl-Enter to run, Cmd/Ctrl-/ to comment
go
xxxxxxxxxx
29
type Main struct {
ShapeClasses []Shape
Shapes []Shape
}
func (m *Main) shapesCalculation(n int){
for i := 0; i < n; i++ {
fmt.Println("Enter the shape type\n1) Rectangle\n2) Square\n3) Circle\nInput : ")
var select int
fmt.Scanln(&select)
if select > 3 || select < 1 {
fmt.Println("Please enter a valid value")
continue
}
shape := m.ShapeClasses[select-1]
shape.inputFromUser()
m.Shapes = append(m.Shapes, shape)
}
var total float64
for _, shape := range m.Shapes {
total += shape.getArea()
}
var average float64
if len(m.Shapes) != 0 {
average = total / float64(len(m.Shapes))
}
fmt.Printf("The average of all shapes' area is : %f\n", average)
}
OUTPUT
:001 > Cmd/Ctrl-Enter to run, Cmd/Ctrl-/ to comment