TaskBuilder.js (Version que a mi parecer deberia ser)
A mi parecer para ingresar los campos de deadline y priority se debe hacer uso de una instancia TaskDecorator, ya que por defecto la instancia Task está preparada para recibir solamente el id y description mientras que con TaskDecorator añade más funcionalidades (Justamente la funcion de este sistema de diseño)
exportclassTaskDecorator{constructor(task, options){this.task= task;this.priority="";this.deadline="";this.checkDeadlineFormat(options.deadline);this.checkPriority(options.priority);}checkDeadlineFormat(deadline){const regex =/\d{4}-\d{2}-\d{2}/;const isValidFormat = regex.test(deadline);if(isValidFormat){this.deadline= deadline;}else{this.deadline="2023-04-19";}}checkPriority(priority){const options =["high","medium","low","alta","media","baja"];const isValidPriority = options.some((option)=> option == priority.toLowerCase());if(isValidPriority){this.priority= priority.toLowerCase();}else{this.priority="baja";}}assignUser(user){if(user instanceofUser){this.task.assignUser(user);}else{thrownewError("Debe pasar como parametro una instancia de User");}}completeTask(){this.task.completeTask();}notifyUsers(){this.task.notifyUsers();}}
TaskManager.js
import{Task}from"./exercise";exportclassTaskManager{constructor(){this.tasks=[];}staticgetInstance(){if(!TaskManager.instance){TaskManager.instance=newTaskManager();}returnTaskManager.instance;}addTask(task){if(task instanceofTask){this.tasks.push(task);}else{thrownewError("Debe pasar como parámetro una instancia de tarea");}}getTasks(){returnthis.tasks;}getTaskById(id){const task =this.tasks.find((task)=> task.id== id);return task ? task :null;}}
exportclassUser{constructor(name){this.name= name;}notify(task){return`La tarea ${task.id} fue completada`;}}
exercise.js
import{User}from"./User"exportclassTask{constructor(id, description){this.id= id;this.description= description;this.completed=false;this.users=[];}assignUser(user){if(user instanceofUser){this.users.push(user);}else{thrownewError("Debe pasar como parametro una instancia de User");}}completeTask(){this.completed=true;this.notifyUsers();}notifyUsers(){this.users.forEach((user)=> user.notify(this));}}
Pensé lo mismo con la clase TaskBuilder.
P.D.: Geniales las validaciones que hiciste para deadline y priority.
Pensé que le faltaría algo si no se ponían validaciones 😂
Mi solución:
.
Tuve problemas con la clase TaskBuilder porque no me quedaba claro si, al tener los datos priority y deadline, debía quedar con la misma estructura de la clase Task o TaskDecorator.
Para la clase Task, en el método assignUser() no se menciona que se debe hacer la verificación de que el usuario es una instancia de la clase User. Y en el enunciado no se muestra que reciba parámetros (aunque esto es bastante obvio).
exportclassUser{constructor(name){this.name= name
}notify(task){console.log(`${this.name} ha sido notificado de que la tarea ${task.id} se completó`)}}
exercise.js
import{User}from"./User"exportclassTask{constructor(id, description){this.id= id
this.description= description
this.completed=falsethis.users=[]}assignUser(user){if(user instanceofUser){this.users.push(user)}else{thrownewError("El usuario no existe")}}completeTask(){this.completed=truethis.notifyUsers()}notifyUsers(){this.users.forEach(user=> user.notify(this))}}
Gracias por el feedback! 💪 Me pongo ya mismo a corregir el ejercicio 🙌
Es necesario hacer este comentario, porque el tiempo que se pierde tratando de resolver un posible "error" que tenemos en nuestro código, cuando realmente el error proviene de una documentación que no aclara todos los requerimientos del ejercicio es extremadamente molesto.
Por favor equipo Platzi e instructor, se requiere que este curso completo se verifique, documentaciones, ejercicios, etc. Es muy frecuente la presencia de errores en todo. Esto lo hago como recomendación porque imagínense si para uno es molesto que tiene experiencia en el area, que ha de ser para una persona que esta iniciando en el mundo del desarrollo.
Esto es lo único negativo que puedo mencionar del curso, mala documentación en muchos casos.
exportclassUser{constructor(name){this.name= name;}notify(task){console.log(`Usuario ${this.name}: La tarea "${task.description}" ha sido completada.`);}}
💚Mi solución 💚
🛡️MURO ANTI-SPOILERS🛡️
!hamster
exercise.js (Task)
import{User}from"./User"exportclassTask{constructor(id, description){this.id= id
this.description= description
this.completed=falsethis.users=[]}assignUser(user){if(!(user instanceofUser))thrownewError("Not a user")this.users.push(user)}completeTask(){this.completed=truethis.notifyUsers()}notifyUsers(){this.users.forEach(user=> user.notify(this))}}
User.js
exportclassUser{constructor(name){this.name= name
}notify(task){console.log(`El usuario ${name} ha sido notificado de que "${task.id}:${task.description}" ha sido completada.`)}}
import{User}from"./User"exportclassTask{constructor(id, description){// Tu código aquí 👈this.id= id;this.description= description;this.completed=false;this.users=[];}assignUser(user){// Tu código aquí 👈if(!(user instanceofUser))thrownewError("No existe el usuario a registrar");this.users.push(user);}completeTask(){// Tu código aquí 👈this.completed=true;this.notifyUsers();}notifyUsers(){// Tu código aquí 👈for(let user ofthis.users) user.notify(this);}}
User.js
exportclassUser{constructor(name){// Tu código aquí 👈this.name= name;}notify(task){// Tu código aquí 👈return`La tarea ${task.id} fue completada`;}}
TaskManager.js
import{Task}from"./exercise";exportclassTaskManager{constructor(){// Tu código aquí 👈this.tasks=[];}staticgetInstance(){// Tu código aquí 👈if(!TaskManager.instance){TaskManager.instance=newTaskManager();}returnTaskManager.instance;}addTask(task){// Tu código aquí 👈if(!(task instanceofTask))thrownewError('Tarea no valida');this.tasks.push(task);}getTasks(){// Tu código aquí 👈returnthis.tasks;}getTaskById(id){// Tu código aquí 👈if(this.tasks.some(task=> task.id=== id))returnthis.tasks.find(task=> task.id=== id);elsereturnnull;}}
TaskDecorator.js
exportclassTaskDecorator{constructor(task, options){// Tu código aquí 👈this.task= task;this.deadline= options.deadline;this.priority= options.priority;}assignUser(user){// Tu código aquí 👈if(!(user instanceofUser))thrownewError('No es una instancia de User');this.task.assignUser(user);}completeTask(){// Tu código aquí 👈this.task.completeTask();}notifyUsers(){// Tu código aquí 👈this.task.notifyUsers(this);}}
TaskBuilder.js
import{Task}from"./exercise";exportclassTaskBuilder{constructor(){// Tu código aquí 👈this.id=undefined;this.description='';this.completed=undefined;this.users=[];this.deadline='';this.priority='';}setId(id){// Tu código aquí 👈this.id= id;}setDescription(description){// Tu código aquí 👈this.description= description;}setCompleted(completed){// Tu código aquí 👈this.completed= completed;}setUsers(users){// Tu código aquí 👈this.users= users;}setDeadline(deadline){// Tu código aquí 👈this.deadline= deadline;}setPriority(priority){// Tu código aquí 👈this.priority= priority;}build(){// Tu código aquí 👈const task =newTask(this.id,this.description);this.users.forEach(user=> task.assignUser(user)); task.deadline=this.deadline; task.priority=this.priority;return task;}}
Authorization.js
exportclassAuthorization{checkAuthorization(user, task){// Tu código aquí 👈if(!task.users.some(tkuser=> tkuser === user))thrownewError('No autorizado');returntrue;}}
import{User}from"./User"exportclassTask{constructor(id, description){this.id= id;this.description= description;this.completed=false;this.users=[];}assignUser(user){if(user instanceofUser){this.users.push(user);}else{thrownewError("Isnt a user instance");}}completeTask(){this.completed=true;this.notifyUsers();}notifyUsers(){this.users.forEach(user=> user.notify(this));}}
++User.js++
exportclassUser{constructor(name){this.name= name;}notify(task){return`The task with ID ${task.id} has been completed by ${this.user}`;}}
++TaskManager.js++
import{Task}from"./exercise";exportclassTaskManager{constructor(){if(!TaskManager.instance){this.tasks=[]TaskManager.instance=Object.freeze(this)}returnTaskManager.instance}staticgetInstance(){returnnewTaskManager()}addTask(task){if(task instanceofTask){this.tasks.push(task);}else{throwError(`Not is a instance of Task`);}}getTasks(){returnthis.tasks;}getTaskById(id){let search =this.tasks.findIndex(task=> task.id=== id);if(!search){returnthis.tasks[search];}returnnull;}}
import{User}from"./User"exportclassTask{constructor(id, description){this.id= id
this.description= description
this.completed=falsethis.users=[];}assignUser(user){if(!(user instanceofUser))thrownewError('no es instancia de User')this.users.push(user)}completeTask(){this.completed=true;this.notifyUsers()}notifyUsers(){for(let user ofthis.users){ user.notify(this)}}}
User.js
exportclassUser{constructor(name){this.name= name
}notify(task){console.log(`La tarea '${task.name}' fue completada`)}}
TaskManager.js
import{Task}from"./exercise";exportclassTaskManager{constructor(){this.tasks=[]}staticgetInstance(){if(!TaskManager.instance){TaskManager.instance=newTaskManager();}returnTaskManager.instance;}addTask(task){if(!task instanceofTask)thrownewError("No es una instancia de Task");this.tasks.push(task)}getTasks(){returnthis.tasks}getTaskById(id){returnthis.tasks.find(t=> t.id=== id)||null;}}
taskDecorator.js
import{Task}from"./exercise.js"exportclassTaskDecoratorextendsTask{constructor(task, options){super(task)this.task= task
this.priority= options.prioritythis.deadline= options.deadline}assignUser(user){console.log('Asignando usuario...')this.task.assignUser(user)}completeTask(){console.log('Marcando la tarea como completada...')this.task.completeTask()}notifyUsers(){console.log('Notificando a todos los usuarios...')this.task.notifyUsers()}}
import{User}from"./User"exportclassTask{constructor(id, description){this.id= id;this.description= description;this.completed=false;this.users=[];}assignUser(user){if(user instanceofUser){this.users.push(user);}else{thrownewError("user no es una instancia de User");}}completeTask(){this.completed=true;this.notifyUsers();}notifyUsers(){this.users.forEach(user=> user.notify(this));}}
import{Task}from"./exercise.js";exportclassTaskBuilderextendsTask{constructor(task){super(task)}setId(id){super.id= id
returnthis}setDescription(description){super.description= description
returnthis}setCompleted(completed){super.completed= completed
returnthis}setUsers(users){for(let user in users){super.assignUser(users[user])}returnthis}setDeadline(deadline){super.deadline= deadline
returnthis}setPriority(priority){super.priority= priority
returnthis}build(){returnthis}}
import{Task}from"./exercise.js";exportclassTaskManager{constructor(){if(!TaskManager.instance){this.tasks=[]TaskManager.instance=Object.freeze(this)}returnTaskManager.instance}staticgetInstance(){returnnewTaskManager()}addTask(task){ task instanceofTask?this.tasks.push(task):newError('no es una tarea o no hereda de Task')}getTasks(){returnthis.tasks}getTaskById(id){returnthis.tasks.find(task=> task.id=== id)||null}}
User:
exportclassUser{constructor(name){this.name= name
}notify(task){return`${this.name}: La tarea (${task.description}) ha sido completada`}}
exercise:
import{User}from"./User.js"exportclassTask{constructor(id, description){this.id= id
this.description= description
this.users=[]this.completed=false}assignUser(user){if(user instanceofUser)this.users.push(user)elsethrownewError('no es user')}completeTask(){this.completed=truereturnthis.notifyUsers()}notifyUsers(){const responses =[]this.users.forEach(user=> responses.push(user.notify(this)))return responses.join('\n')}}
Solución… 😄
.
.
.
.
.
.
Authorization.js:
.
exportclassAuthorization{checkAuthorization(user, task){const authorized = task.users.includes(user);if(authorized){returntrue;}thrownewError("El usuario no está autorizado para esta tarea");}}
import{User}from"./User"exportclassTask{constructor(id, description){this.id= id;this.description= description;this.completed=false;this.users=[];}assignUser(user){if(!(user instanceofUser)){thrownewError("No hereda de la clase user")}this.users.push(user);}completeTask(){this.completed=true;this.notifyUsers();}notifyUsers(){this.users.forEach(user=>{ user.notify(this);});}}
exportclassUser{constructor(name){this.name= name;}notify(task){console.log(`La tarea ${task.description} ha sido completada`);}}
import{Task}from"./exercise";exportclassTaskManager{constructor(){this.tasks=[];}staticgetInstance(){if(!TaskManager.instance){TaskManager.instance=newTaskManager();}returnTaskManager.instance;}addTask(task){if(task instanceofTask){this.tasks.push(task);}else{thrownewError('La tarea no es válida');}}getTasks(){returnthis.tasks;}getTaskById(id){returnthis.tasks.find(task=> task.id=== id)||null;}}
exportclassAuthorization{checkAuthorization(user, task){// Tu código aquí 👈const isAuthenticated = task.users.findIndex((taskUser)=> taskUser.name=== user.name)!==-1;if(!isAuthenticated)throwError("Not authorized");console.log(`User: ${user.name} is authorized`); task.completeTask();}}
exercise
import{User}from"./User.mjs";exportclassTask{constructor(id, description){// Tu código aquí 👈this.id= id;this.description= description;this.completed=false;this.users=[];}assignUser(user){// Tu código aquíif(user instanceofUser){this.users.push(user);returnthis.users;}}completeTask(){// Tu código aquí 👈if(this.users.length===0){console.log("Cannot complete task, no user assigned to this task");return;}this.completed=true;this.notifyUsers();}notifyUsers(){// Tu código aquí 👈this.users.forEach((user)=> user.notify(this));}}
TaskBuilder
import{Task}from"./excercise.mjs";exportclassTaskBuilder{constructor(){// Tu código aquí 👈this.id=0;this.description="";this.completed=false;this.users=[];this.deadline=null;this.priority=null;}setId(id){// Tu código aquí 👈this.id= id;returnthis;}setDescription(description){// Tu código aquí 👈this.description= description;returnthis;}setCompleted(completed){// Tu código aquí 👈this.completed= completed;returnthis;}setUsers(users){// Tu código aquí 👈this.users= users;returnthis;}setDeadline(deadline){// Tu código aquí 👈this.deadline= deadline;returnthis;}setPriority(priority){// Tu código aquí 👈this.priority= priority;returnthis;}build(){// Tu código aquí 👈const task =newTask(this.id,this.description);this.users.forEach((user)=> task.assignUser(user)); task.priority=this.priority; task.deadline=this.deadline;return task;}}
TaskDecorator
exportclassTaskDecorator{constructor(task, options){// Tu código aquí 👈this.task= task;this.deadline= options.deadline;this.priority= options.priority;}assignUser(user){// Tu código aquí 👈this.task.assignUser(user);}completeTask(){// Tu código aquí 👈this.task.completeTask();}notifyUsers(){// Tu código aquí 👈this.task.notifyUsers();}}
TaskManager
import{Task}from"./excercise.mjs";exportclassTaskManager{static instance =null;constructor(){// Tu código aquí 👈this.tasks=[];}staticgetInstance(){// Tu código aquí 👈if(TaskManager.instance===null){TaskManager.instance=newTaskManager();}returnTaskManager.instance;}addTask(task){// Tu código aquí 👈if(!(task instanceofTask))return;if(this.tasks.findIndex((managerTask)=> managerTask.id=== task.id)!==-1){throwError("This task already exists in the Task manager");}this.tasks.push(task);console.log(`Task added: ${task.description}`);}getTasks(){// Tu código aquíif(this.tasks.length===0){console.log("The tasks list is empty");return;}console.log(this.tasks);returnthis.tasks;}getTaskById(id){// Tu código aquí 👈const task =this.tasks.find((task)=> task.id=== id);console.log(task);return task ? task :null;}}
User
exportclassUser{constructor(name){// Tu código aquí 👈this.name= name;}notify(task){// Tu código aquí 👈console.log(`The task: ${task?.description} is completed.`);}}
Se logró :D, sude la gota amarga pero se logró:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Authorization.js
exportclassAuthorization{checkAuthorization(user, task){if(task.users.includes(user)){ task.completeTask();}else{thrownewError("El usuario no esta autorizado para completar la tarea");}}}
import{Task}from"./exercise";exportclassTaskManager{constructor(){this.tasks=[];}staticgetInstance(){if(!TaskManager.instance){TaskManager.instance=newTaskManager();}returnTaskManager.instance;}addTask(task){if(task instanceofTask){this.tasks.push(task);}else{thrownewError(`La tarea no es valida`)}}getTasks(){returnthis.tasks;}getTaskById(id){let foundTask =this.tasks.find(task=> task.id=== id);if(foundTask){return foundTask;}else{returnnull;}}}
User.js
exportclassUser{constructor(name){this.name= name;}notify(task){return`La tarea ${task} ha sido completada`;}}
excercise.js
import{User}from"./User"exportclassTask{constructor(id, description){this.users=[];this.id= id;this.description= description;this.completed=false;}assignUser(user){if(user instanceofUser){this.users.push(user);}else{thrownewError(`No se puede asignar si no es de la clase User`)}}completeTask(){this.completed=true;this.notifyUsers();}notifyUsers(){this.users.forEach(user=>{ user.notify(this)})}}