Dynamically constructing composition object

2019-08-18 16:47发布

I have a review table for courses which is made up of multiple objects for different courses.A student should review the courses he is enrolled in every month.The Math,Science,History are tables by themselves but I store foreign keys in the Review table so that each review for the courses is associated with the respective table.

NOTE:a student can only be enrolled in two courses

@Entity
class Review{
//multiple time fields here here

@OneToOne(cascade=CascadeType.ALL,optional=true)
@JoinColumn(name="math_review_id")
Math m;

@OneToOne(cascade=CascadeType.ALL,optional=true)
@JoinColumn(name="science_review_id")
Science s;

@OneToOne(cascade=CascadeType.ALL,optional=true)
@JoinColumn(name="history_review_id")           
History h;

}

Super Class

 @MappedSuperclass
 class Course {
   @Id
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   @Column(name="id")
   int id;

   @ManyToOne(fetch = FetchType.LAZY, 
        cascade = { CascadeType.DETACH,
                    CascadeType.MERGE, 
                    CascadeType.PERSIST,
                    CascadeType.REFRESH },
                    )
   @JoinColumn(name = "student_id")
   private Student student;
 }

Subclass History

@Entity
 class History extends Course{
//fields specific to history course
 }

Subclass Math

@Entity
class Math extends Course{
//fields specific to math course
}

Student class

@Entity
class Student{
//fields name,id,...
@OneToMany(mappedBy = "student", 
           cascade = CascadeType.ALL,
           fetch = FetchType.LAZY)
private List<Review> reviewsList;
}

I check what courses the student is enrolled in and initialize the Math,Science,History accordingly.I pass a Review object to my reviews.jsp and save the returned @ModelAttribute using hibernate.I dont initialize the courses the student is not enrolled in.I thought uninitialized objects wont be saved but hibernate makes null entries even if not initialized ( I think because they are mapped to a table and are inside a persistent class). I need help how to dynamically construct Review object just with the courses the student is enrolled in.My current design might have flows,any better design suggestions are much appreciated(I have minimal experience in Java and hibernate)

1条回答
爷、活的狠高调
2楼-- · 2019-08-18 17:28

As a suggestion I think you should be weary of creating a class per course. Would it not be sufficient to have a Course class which has a member of type, which could be Math, Science or History. Even that type could itself be an entity: CourseType, which you could have entries for so in your code there would be no Math, Science or History. Instead those are in a database, instead of code.

The Review object would only then interact with a Course. Just think of also all the work you will need to do when you add another course. You will have to update many different files and even add a table in your database, I don't believe you should need to do that.

I imagine you may have some differences between Course classes, and it may be a bit awkward having all these in one class. But from my experience this is typically worth doing, as it drastically reduces the amount of code and allows for more courses to be added without code.

Edit I still strongly recommend you consider reevaluating your decision of 1 class per a course, but anyway your decision. It's really unclear what this Review object is. You say that there are only 2 courses a student will be enrolled in so I imagine that 2 of these fields are null, then. But then it confuses me because you have one class per course, but you have an overeaching review object across all subjects. I would have expected to see:

class EnrolementReview{
    Course courseA;
    Course courseB;
}

Otherwise if your review depends on fields in your Math, or Science courses, I would expect to have a review class for each course:

class MathReview {
    MathCourse course;
}

Or you might have a generic base class for review

abstract class CourseReview<C extends Course> {
    C course;
}

if you had common functionality between them. And then an SemesterReview class for reviewing 2 classes in a semester:

class SemesterReview{
    CourseReview review1;
    CourseReview review2;
}

As far as dynamic composition, IMO I don't think it makes much sense in a statically typed language this notion. You have builder patterns and cake patterns and the like. Some programming languages have some nice stuff in this area like Scala traits but the benefits are very limited, nothing you couldn't do in Java wait a couple of class casts which are a bit evil but it gets the job done.

For all the many permutations of design patterns and methods available to you as a developer, I think it's a bit easier to look at some of the outputs of your design decision, such as:

  • How many classes am I going to write?
  • Will I be able to add more courses without writing code and changing the database tables?
  • Can somebody else understand my code?

Last Edit In regards to many null field being a concern, you have some options. Either you have null fields (which you seem to not like), or you do something like encapsulate variable types as an entity (for example each course has a list of Strings, Integers, Doubles etc), which I've seen used quite a bit in many different situations. That works out ok but you do delay some areas which may have been at compile to run-time, as you may need an integer which has a variable name of scienceCategory etc. It also can be awkward if you have some structured data. In general that approach is only good if you really don't know how a client is going to use your system and so you expose more of it to them to use.

However my personal favourite, is to follow the natural composition of your class, and encapsulate families of variables into their own class, which you expect wont always be applicable, as in if one isn't applicable all the others wont be either. The logic whether these classes are present should be very explicit however, either they should be Optional<ScienceInformation> or you should have some methods somewhere which returns a boolean whether or not this option should exist or not. Then operations can be performed on those options in the system you create. Just need to be careful you don't create objects which are too deeply nested as in objects which are made up of objects, which are made up of objects, (not always a problem but usually it is).

But really I don't think it's super important what way you choose, none of them will give you the comfy feeling that writing a class gives you. Just need to think about how you are going to abstract over these entities (eg. Course) in a way which will not lead you to an un-maintainable mess. You clearly have a very complete knowledge of your domain but you should write your code in a way where I (somebody who doesn't know about how many courses are in a semester) can read the code and then find that out without reading comments (that would be cheating), what the answer to that question is.

查看更多
登录 后发表回答