Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Oop exercise #416

Merged
merged 8 commits into from
Sep 26, 2022
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions submissions/OlexiyDobroskok/OOP_exercise/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
const inhabitantDefaultProperties = {
species: "No species",
name: "No name",
gender: "No gender",
saying: "Hello",
friends: "",
};

const humanDefaultProperties = {
hands: 2,
legs: 2,
};

const petsDefaultProperties = {
paws: 4,
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be a better approach to have defaults within class definitions. Not necessarily in form of explicit const definitions. KISS

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


class Inhabitant {
static worldPopulation = [];
constructor({
species,
name,
gender,
saying,
friends,
} = inhabitantDefaultProperties) {
this.species = species ?? inhabitantDefaultProperties.species;
this.name = name ?? inhabitantDefaultProperties.name;
this.gender = gender ?? inhabitantDefaultProperties.gender;
this.saying = saying ?? inhabitantDefaultProperties.saying;
this.friends = friends ?? inhabitantDefaultProperties.friends;
Inhabitant.worldPopulation.push(this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a good idea to populate world from within inhabitants.
There is a Factory pattern in SW design, but this is not the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a good idea to populate world from within inhabitants. There is a Factory pattern in SW design, but this is not the case.

Can I create a separate function that will create and push objects into an array?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. Creating World class would be an overkill at this stage of project development.
But please avoid .push. Array methods provide more semantic ways to solve this.
And you will probably want to help inhabitants make friends after they are born. At least exisiting inhabitants cannot make friends with those who are not born yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I abandoned this idea because it was originally intended to simplify the creation of the world, but Later there are problems with withdrawal of friends.What method can you recommend to replace the push?It seemed to me very convenient to work initially with an empty array. (

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this fragment. I agree that .push is a way to go.
The only thing remains: it is a world that consists of Inhabitants rather than world is a part of any Inhabitants.
Sure, syntax allows us to do this and make a static prop looks attractive. But having world as a part of inhabitant is counter-intuitive.
World can be a collection of inhabitants. Simplest collection is JS array. If we wanted some world-wide operations we would have multiple functions for those operations and it would make sense to scope them under class World.

}

addFriend({ name }) {
this.friends += name + "; ";
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the requirements:

Friends list is a list of objects refs rather than names (strings)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


introduceYourSelf() {
if (this.friends === "") {
this.friends = "Looking for friends!";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will happen if we .addFriend after first call of .introduceYourSelf?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@

What will happen if we .addFriend after first call of .introduceYourSelf?

@OleksiyRudenko Instead of an empty array, I get a string...) Done)

}
return `<strong>${this.saying}! My name is ${this.name}. Species: ${this.species}. Gender: ${this.gender}. Friends: ${this.friends} </strong>`;
}
}

class Human extends Inhabitant {
constructor({
name,
gender,
saying,
legs,
hands,
friends,
} = humanDefaultProperties) {
super({ species: "human", name, gender, saying, friends });
this.hands = hands ?? humanDefaultProperties.hands;
this.legs = legs ?? humanDefaultProperties.legs;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just to set default value the same way it is done for species?
This is not a rhetoric question.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve overdone the default values a little bit. =))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

introduceYourSelf() {
return (
super.introduceYourSelf() +
`<strong>I have ${this.hands} hands and ${this.legs} legs!</strong>`
);
}
}

class Man extends Human {
constructor({ name, saying, friends, legs, hands }) {
super({ name, gender: "male", saying, legs, hands, friends });
}
}

class Woman extends Human {
constructor({ name, saying, friends, legs, hands }) {
super({ name, gender: "female", saying, legs, hands, friends });
}
}

class Pets extends Inhabitant {
constructor({
species,
name,
gender,
paws,
saying,
friends,
} = petsDefaultProperties) {
super({ species, name, gender, saying, friends });
this.paws = paws ?? petsDefaultProperties.paws;
}
introduceYourSelf() {
return (
super.introduceYourSelf() + `<strong>I have ${this.paws} paws!</strong>`
);
}
}

class Cat extends Pets {
static meow;
constructor({ name, gender, saying = "¡miau miau", friends, paws }) {
super({
species: "cat",
name,
gender,
paws,
saying,
friends,
});
Cat.meow = this.saying;
}
}

class Dog extends Pets {
static bark;
constructor({ name, gender, saying = "¡guau guau", friends, paws }) {
super({
species: "dog",
name,
gender,
paws,
saying,
friends,
});
Dog.bark = this.saying;
}
}

class CatWoman extends Woman {
constructor({ name, saying = "", friends, legs, hands }) {
super({ name, saying, friends, legs, hands });
this.saying = Cat.meow + " " + saying;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use static property is a good start in the right direction.
But here is the problem: if we change cat's defaut meow (which is allowed by Cat class API), cat-women's saying will be out of sync. Can you devise a way to bind their saying more tightly? You are only one step away from the solution.

Copy link
Contributor Author

@OlexiyDobroskok OlexiyDobroskok Sep 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OleksiyRudenko The easiest way I see is to assign a default value to the static property of the cat:

Cat.meow = "¡miau miau";
this.saying = Cat.meow;

but then all cats lose their identity and it makes me sad =)))
Is this the right way?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as property holds a primitive value the tie is weak, i.e. simply copied once. Strings, numbers and booleans are primitives. We need something that is passed by reference. These are JS objects (arrays and functions are also objects). Class methods can also be static. There are also very specific methods - getters and setters.
Given the above find a solution that will help to both meet requirements and minimize impact on code to keep it readable (i.e. we do not want dogs and humans to have added complexity just becase we need to resolve a matter between cats and cat-women).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OleksiyRudenko Tried to bind Woman and cat by static method. Looks strange)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does. Truth is that hybrids do not fit OOP hierarchical nature really well.
Composition is a better pattern in similar cases.
The purpose of this part of task was exactly to see the weirdness of how it has to be implemented in OOP paradigm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OleksiyRudenko Good task. At a glance nothing difficult, but on the small details forces to revise a lot of materials). Do I still have to make some adjustments to the task?

}
}

const manJose = new Man({ name: "José", saying: "Hola, amigo" });
const womanMartina = new Woman({ name: "Martina", saying: "Buenos días" });
const catLalo = new Cat({ name: "Lalo", gender: "female" });
const dogPako = new Dog({ name: "Pako", gender: "male" });
const catwomanNerea = new CatWoman({ name: "Nerea", saying: "muchachos" });

manJose.addFriend(catwomanNerea);
womanMartina.addFriend(dogPako);
catwomanNerea.addFriend(catLalo);
catwomanNerea.addFriend(manJose);

function showWorldPopulation() {
const inhabitantNames = Inhabitant.worldPopulation.map(
(inhabitant) => inhabitant.name
);
print(
`<strong>Population: ${Inhabitant.worldPopulation.length} inhabitants! It is: ${inhabitantNames}</strong>`
);
Inhabitant.worldPopulation.forEach((inhabitant) =>
print(inhabitant.introduceYourSelf())
);
}

showWorldPopulation();