The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
Famous M. Ighodaro wrote:I want to be able to print each course later and the number of students enrolled on it. And also print all the student and the number of course each student enrolled in.
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
Carey Brown wrote:I believe that would break the principle. You'd end up with Course having a List<Student> and Student having a List<Course>. Then the problem becomes going to two places to add a Student to a Course.
You could have an Enrollment class, for example, with Map<Student,List<Course>> and also Map<Course,List<Student>>. Then you only have to go to the Enrollment object to add a Student to a Course and both maps would be maintained in sync.
Edit: Probably "Set" would be better than List.
Junilu Lacar wrote:
Famous M. Ighodaro wrote:I want to be able to print each course later and the number of students enrolled on it. And also print all the student and the number of course each student enrolled in.
This is the part that most likely will lead to breaking the SRP. Printing a class roster and printing a coarse load are different responsibilities from maintaining enrollment information. If you have methods in a Course class that maintain the roster of students and print the roster of students taking the course then that is a violation of the SRP. Likewise in a Student class if you have methods that maintain information about course load and printing the coarse load. The responsibilities of maintaining the list and printing the list should be separated. Here's why: If you need to change the way the printed list is formatted, ordered, or filtered, it has nothing to do with how the list is maintained. Maintaining the list is therefore a different responsibility from printing the list.
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
I wrote:there is at least one logic bug
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
There are three kinds of actuaries: those who can count, and those who can't.
Piet Souris wrote:
2. Too much information is recorded. What more than a Map<Lesson, Set<Student>> is required? It is easy to derive any information from this map.
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
Piet Souris wrote:
1. I like that enrollment class (haven't quite understood the objections sofar, but I'll give it anoher thorough read). I do not like to mutate a Lesson and a Student whenever a Lesson-Student is added.
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
Junilu Lacar wrote:You could conceivably simplify it further to be just a collection of (Course, Student) tuples. Having a Map<Lesson, Set<Student>> or Map<Student, Set<Lesson>> is really just an optimization.
There are three kinds of actuaries: those who can count, and those who can't.
Junilu Lacar wrote:Let's dig into this a little more. I think I have an idea as to why you don't like this but as good developers, we have to articulate our reasons for choosing one design over another beyond just liking or not liking it. I could come up with a few ways to reason against the design I showed as well but let's talk about your reasons first.
There are three kinds of actuaries: those who can count, and those who can't.
Piet Souris wrote:
I have the picture in mind that a Lesson (or Course) should be something that is as stable as possible. For instance: you have the Lesson "Math for third years", containing a list of subjects and requirements about what a Student is supposed to be capable of, once done. That should hardly change.
Then there are the concrete versions of this, with who is the teacher, on what dates and times it is given, a set of students, et cetera. As said, I would store that in a separate class.
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
Carey Brown wrote:One reason I gravitate to using an Enrollment class is it more closely matches a database implementation of a table with two columns and two indexes. So a migration to a database for persistence would be relatively painless.
The best ideas are the crazy ones. If you have a crazy idea and it works, it's really valuable.—Kent Beck
How to Ask Questions | How to Answer Questions | Format Your Code
Junilu Lacar wrote:I actually like this perspective because it aligns with the Person, Place, or Thing archetype from Coad's four archetypes (...)
Then, all you really need is to maintain a Set<Offering> to get class rosters using streams, collectors, and grouping by Offering. By the same token, you can also query the Set<Offering> to get each student's set of class offerings taken for a particular term. The mechanism to keep parallel collections synchronized wouldn't even be necessary, which just goes to show that it was really just another premature optimization that only made the code and design more complex.
There are three kinds of actuaries: those who can count, and those who can't.
Junilu Lacar wrote:Previously,
I wrote:there is at least one logic bug
The design has a number of problems related to breaking the encapsulation of Student and Lesson and misplacing the responsibility of enforcing the following rules:
1. A student can only enroll in a limited number of courses. (Apparently, no more than 2)
2. A course/lesson can only accept a limited number of students as determined by Lesson.getCapacity()
Consider what happens when a student tries to enroll in a course that is already at capacity. I haven't tested it but from what I can tell by just looking at the code, even though a student doesn't get added to a lesson because it is already at full capacity, the lesson will still get added to the student's list of lessons taken as long as they haven't yet enrolled in the maximum number of lessons allowed per student.
Junilu Lacar wrote:And here's my Student class implementation based on the tests I have written so far:
synchronizeEnrollment(Course) is the callback method I alluded to earlier in this thread. It has package-private (default) scope by design.
Campbell Ritchie wrote:Why have you made the Enrollment class a singleton? I don't think that is the correct way to write a singleton anyway.
Everybody's invited. Even this tiny ad:
SKIP - a book about connecting industrious people with elderly land owners
https://coderanch.com/t/skip-book
|