Need help in OOP

class Shape {
radius: number;
length: number;
breadth: number;
base: number;
height: number;

constructor(radius: number) {
this.radius = radius;
this.length = 0;
this.breadth = 0;
this.base = 0;
this.height = 0;
}
}

class Circle extends Shape {
constructor(radius: number) {
super(radius);
}

getArea(): number {
return Math.PI * this.radius * this.radius;
}
}

class Rectangle extends Shape {
constructor(length: number, breadth: number) {
super(0);
this.length = length;
this.breadth = breadth;
}

getArea(): number {
return this.length * this.breadth;
}
}

class Triangle extends Shape {
constructor(base: number, height: number) {
super(0);
this.base = base;
this.height = height;
}

getArea(): number {
return (this.base * this.height) / 2;
}
}

const circle = new Circle(10);
const radius = new Rectangle(3, 4);
const triangle = new Triangle(5, 6);

console.log(circle.getArea());
console.log(radius.getArea());
console.log(triangle.getArea());
class Shape {
radius: number;
length: number;
breadth: number;
base: number;
height: number;

constructor(radius: number) {
this.radius = radius;
this.length = 0;
this.breadth = 0;
this.base = 0;
this.height = 0;
}
}

class Circle extends Shape {
constructor(radius: number) {
super(radius);
}

getArea(): number {
return Math.PI * this.radius * this.radius;
}
}

class Rectangle extends Shape {
constructor(length: number, breadth: number) {
super(0);
this.length = length;
this.breadth = breadth;
}

getArea(): number {
return this.length * this.breadth;
}
}

class Triangle extends Shape {
constructor(base: number, height: number) {
super(0);
this.base = base;
this.height = height;
}

getArea(): number {
return (this.base * this.height) / 2;
}
}

const circle = new Circle(10);
const radius = new Rectangle(3, 4);
const triangle = new Triangle(5, 6);

console.log(circle.getArea());
console.log(radius.getArea());
console.log(triangle.getArea());
is there a better way to do this using OOP? this feels a bit inconsistent to me but im inexperienced in OOP and don't know if there's a better way to do this. would love some help!
42 Replies
Brendonovich
Brendonovich2y ago
I think a more OOP style approach would be for Shape to have abstract function getArea(): number; and the extending classes would define the properties themselves - it doesn’t really make sense for a rectangle to have a radius Imo my library Sceneify is a decent demonstration of OOP with abstract classes and inheritance
nexxel
nexxel2y ago
interesting how would that look like in code? i've never seen an abstract function
Brendonovich
Brendonovich2y ago
It’s like putting a function on a trait in rust You do everything except add the curly braces and body of the function Funnily enough, this example uses the abstract class like a trait
nexxel
nexxel2y ago
hmm, it says abstract methods can only appear in abstract classes need to learn this lol
Brendonovich
Brendonovich2y ago
Ah yeah you’ll need to make the class abstract too An abstract class can’t be instantiated, but classes that inherit it can
nexxel
nexxel2y ago
abstract class Shape {
radius: number;
length: number;
breadth: number;
base: number;
height: number;

constructor(radius: number) {
this.radius = radius;
this.length = 0;
this.breadth = 0;
this.base = 0;
this.height = 0;
}

abstract getArea(): number;
}

class Circle extends Shape {
constructor(radius: number) {
super(radius);
}

getArea(): number {
return Math.PI * this.radius * this.radius;
}
}

class Rectangle extends Shape {
constructor(length: number, breadth: number) {
super(0);
this.length = length;
this.breadth = breadth;
}

getArea(): number {
return this.length * this.breadth;
}
}

class Triangle extends Shape {
constructor(base: number, height: number) {
super(0);
this.base = base;
this.height = height;
}

getArea(): number {
return (this.base * this.height) / 2;
}
}

const circle = new Circle(10);
const radius = new Rectangle(3, 4);
const triangle = new Triangle(5, 6);

console.log(circle.getArea());
console.log(radius.getArea());
console.log(triangle.getArea());
abstract class Shape {
radius: number;
length: number;
breadth: number;
base: number;
height: number;

constructor(radius: number) {
this.radius = radius;
this.length = 0;
this.breadth = 0;
this.base = 0;
this.height = 0;
}

abstract getArea(): number;
}

class Circle extends Shape {
constructor(radius: number) {
super(radius);
}

getArea(): number {
return Math.PI * this.radius * this.radius;
}
}

class Rectangle extends Shape {
constructor(length: number, breadth: number) {
super(0);
this.length = length;
this.breadth = breadth;
}

getArea(): number {
return this.length * this.breadth;
}
}

class Triangle extends Shape {
constructor(base: number, height: number) {
super(0);
this.base = base;
this.height = height;
}

getArea(): number {
return (this.base * this.height) / 2;
}
}

const circle = new Circle(10);
const radius = new Rectangle(3, 4);
const triangle = new Triangle(5, 6);

console.log(circle.getArea());
console.log(radius.getArea());
console.log(triangle.getArea());
like this?
Brendonovich
Brendonovich2y ago
Ye The reason you’d do it this way is that now you can make a function accept Shape and know that the getArea function will exist
nexxel
nexxel2y ago
ohh that makes sense now
Brendonovich
Brendonovich2y ago
If you move all the properties from Shape to the extending classes, you could turn it into an interface
nexxel
nexxel2y ago
yeah im trying to code up both approaches to this one using adts and one using oop
// adts
interface Circle {
type: "circle";
radius: number;
}

interface Rectangle {
type: "rectangle";
length: number;
breadth: number;
}

interface Triangle {
type: "triangle";
base: number;
height: number;
}

type Shape = Circle | Rectangle | Triangle;

const getArea = (shape: Shape) => {
switch (shape.type) {
case "circle":
return Math.PI * shape.radius * shape.radius;
case "rectangle":
return shape.length * shape.breadth;
case "triangle":
return (shape.base * shape.height) / 2;
}
};

const c: Circle = { type: "circle", radius: 10 };
const r: Rectangle = { type: "rectangle", length: 3, breadth: 4 };
const t: Triangle = { type: "triangle", base: 5, height: 6 };

console.log(getArea(c));
console.log(getArea(r));
console.log(getArea(t));
// adts
interface Circle {
type: "circle";
radius: number;
}

interface Rectangle {
type: "rectangle";
length: number;
breadth: number;
}

interface Triangle {
type: "triangle";
base: number;
height: number;
}

type Shape = Circle | Rectangle | Triangle;

const getArea = (shape: Shape) => {
switch (shape.type) {
case "circle":
return Math.PI * shape.radius * shape.radius;
case "rectangle":
return shape.length * shape.breadth;
case "triangle":
return (shape.base * shape.height) / 2;
}
};

const c: Circle = { type: "circle", radius: 10 };
const r: Rectangle = { type: "rectangle", length: 3, breadth: 4 };
const t: Triangle = { type: "triangle", base: 5, height: 6 };

console.log(getArea(c));
console.log(getArea(r));
console.log(getArea(t));
Brendonovich
Brendonovich2y ago
huh Would never have thought to do that example in that way but yeah it works
nexxel
nexxel2y ago
what were you thinking
Brendonovich
Brendonovich2y ago
Problem is that it couples Shape to the three specific shapes
nexxel
nexxel2y ago
yeah you're gonna have to add other shapes manually
Brendonovich
Brendonovich2y ago
And if this was a library there’d be no way to add more shapes You also lose being able to rely on object prototypes and instanceof
Want results from more Discord servers?
Add your server