User types on library management system - java

I have to build a library management system and i've run into problems while trying to implement user types or profiles. I've already got a superclass user and two other subclasses of User, Student and Teacher, each with their own "characteristics". The thing is i have to implement 7 types of users (5 types of students and 2 types of clerks) based on the number of books they can borrow and the amount of time they can keep the books until they have to return them. Those are the only 2 differences between the classes.
How would you implement this? Inheritance? I'm looking for a clever way to implement this and i would love to hear your thoughts on this.
Thank you very much.

As a good rule of thumb, anywhere you see a noun in a project specification it's a good candidate for a class. If those nouns have relationships in the project spec, they probably aught to have one in your code too.
All of your people would fit in the category of a Userso perhaps this should be an interface they would all inherit. Down from this they appear to fit into two categories, Student and Staff perhaps these should also be abstract classes / interfaces. Then you have your 7 concrete classes. 2 inheriting Staff and 5 inheriting Student.
So you'd end up with something like this..
Of course, this design depends on what every User must do, what every Staff / Student must do but I'll leave the very specific details to you.

You have a "class" per person, which really limits your design; because, if you want to add a student or teacher, you need to start writing a new class.
Classes are templates, and each template is used to construct an "instance of the class" or more specifically an "instance". One template is typically used to construct more than one class (although it is not necessary for a class to be used more than once, using it once (or not using it at all) is fine).
So you could do
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public string getName() {
return this.name;
}
}
public class Staff {
private String name;
public Staff(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
As you can see, there is going to be a lot of duplication between staff and students. getName(), getAge(), getPhoneNumber(), getAddress(), etc can easily be applied to both, which under this structure means that you would have to duplicate those methods for both Student and Staff.
What does both a staff member and a student have in common? They are both People, and many of the common methods are common to all people.
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
public Staff extends Person {
public void teachClass(Class class) {
...
}
}
public Student extends Person {
public void attendClass(Class class) {
...
}
}
This design also creates other issues, as it implies that a Staff member is not a Student, and a Student is not a Staff member. In the real world, sometimes the Staff enrolls for classes, and Students can take on teaching roles (think teacher's aide).
The most flexible method actually doesn't create a structural differentiation between a Student and Staff, it differentiates between the two by ability.
public class Person {
public Person(String name) {
...
}
public void canTeach(Course course) {
teaching.add(course);
}
public void attending(Course course) {
attending.add(course);
}
public boolean isStaff() {
return !teaching.isEmpty();
}
public boolean isStudent() {
return !attending.isEmpty();
}
}
However, this structure is radically different from the example you are being presented in class, and it side-steps the lessons you really are supposed to be learning about inheritance.

Related

Java avoiding code duplication when both classes are almost similar but different packages, but similar functions

There is a literal code in my project,
private List<String> getAddressLines(PartyAddressDTO partyAddressDTO) {
List<String> addressLines = new ArrayList<>();
if (!CollectionUtils.isEmpty(partyAddressDTO.getAddressLines()))
addressLines.addAll(partyAddressDTO.getAddressLines().values());
if (addressLines.isEmpty()) {
if (!StringUtils.isEmpty(partyAddressDTO.getHouseNumber()))
addressLines.add(partyAddressDTO.getHouseNumber());
if (!StringUtils.isEmpty(partyAddressDTO.getStreet()))
addressLines.add(partyAddressDTO.getStreet());
if (!StringUtils.isEmpty(partyAddressDTO.getCity()))
addressLines.add(partyAddressDTO.getCity());
}
return addressLines;
}
This is duplicated at three different places, I was trying to go through sonar analysis and this is the place it shows as duplicated, but the problem is,
com.package.module1.party.PartyAddressDTO
com.package.module2.party.PartyAddressDTO
com.package.module3.party.PartyAddressDTO
In our three different classes, this is the imports, all three belong to different packages, I don't understand why those source modules have been named like this, and I don't have control over their objects, and they don't extend a single interface or anything, but having to duplicate some lines of code in my project is en eyesore to me. Is there anyway to extract such code?
If the properties/methods of PartyAddressDTO class is same for all 3 modules, and you dont have any control on those modules, then the best way to avoid code duplication is to have your own implementation like this: (please ignore the property names and method names)
public class MyPartyAddressDTO {
private String name;
private int age;
public MyPartyAddressDTO(package1.PartyAddressDTO partyAddressDTO1){
this.name = partyAddressDTO1.getName();
this.age = partyAddressDTO1.getAge();
}
public MyPartyAddressDTO(package2.PartyAddressDTO partyAddressDTO2){
this.name = partyAddressDTO2.getName();
this.age = partyAddressDTO2.getAge();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
and use MyPartyAddressDTO throughout your application
Generally, We would have a common module and have an internal pkg, extract the common parts to that place. All other modules would refer common but common would be referred by anyone, so cyclic dependency will be avoided. Move all your common classes over there and you can avoid duplication.

Differentiating Composition and Aggregation programmatically

I was going through below link to figure out differentiation between Composition and Aggregation.
https://www.geeksforgeeks.org/association-composition-aggregation-java/
I am able to understand that Composition implies a relationship where the child cannot exist independent of the parent while Aggregation implies a relationship where the child can exist independently of the parent. But not able to understand how can i differentiate that programmatically . Below is an example of Aggregation and Composition as given in link.In both cases the classes are same in structure except that Student and Department class has an extra variable "name" .As in Composition "child cannot exist independent of the parent ",but here I can create a separate object of Book and use it without adding it to Library.
Aggregation
// student class
class Student
{
String name;
int id ;
String dept;
Student(String name, int id, String dept)
{
this.name = name;
this.id = id;
this.dept = dept;
}
}
/* Department class contains list of student
Objects. It is associated with student
class through its Object(s). */
class Department
{
String name;
private List<Student> students;
Department(String name, List<Student> students)
{
this.name = name;
this.students = students;
}
public List<Student> getStudents()
{
return students;
}
}
Composition
class Book
{
public String title;
public String author;
Book(String title, String author)
{
this.title = title;
this.author = author;
}
}
// Libary class contains
// list of books.
class Library
{
// reference to refer to list of books.
private final List<Book> books;
Library (List<Book> books)
{
this.books = books;
}
public List<Book> getTotalBooksInLibrary()
{
return books;
}
}
As far as I can tell (and maybe somebody else can give a better answer), you can't evaluate if the relationship is aggregation or composition just by looking at Java code. It's the other way around.
First you create a conceptual model of the world. Libraries have books, and cars have wheels. Then you think - does it make sense for a book to exist without a library, or for a wheel to exist without a car, in the context I'm working in. So for example if you are writing a car racing game, you will have no use of wheels outside of cars. But if you are writing some auto-repair application, you will deal with wheels independently of some particular car.
So first you decide if you need aggregation or composition, and then implement it in your code. The implementation could be that object Car has List<Wheel> but you can't tell if it's composition or aggregation just from that. The key is that you interpret the code (implementation) based on your conceptual model and then use it according to that.
If it's composition, the usage it might have some restrictions:
No object other than Car will hold a reference to Wheel.
Wheel might even be a private or package-private class.
If Car is saved in database, when you delete it, you also automatically delete all of its Wheels.
But it's up to you to enforce these restrictions if you decide it's composition.
In the real world, a book can indeed exist in its own right without being owned by a library. But what if, instead, you had a LibraryBook class with fields like dateAcquired and currentBorrower? Using your design, you would still be able to create a LibraryBook instance without a library.
This is where languages like C++ can be more explicit about composition: in C++, an object can hold its parts by value. In Java, every object is handled by a pointer (OK, Java people don't call them pointers; they call them references instead.) This makes it more difficult to differentiate between composition and aggregation. In Java, you do it using careful design.
For example, we can make the LibraryBook class only instantiable through a method of Library:
class Library {
class LibraryBook {
private LibraryBook() {/*private constructor prevents independent instantiation*/}
}
LibraryBook createBook(String title, etc...);
}
Furthermore, if we make LibraryBook's mutator methods only accessible to the Library class, we can ensure that the book remains part of its owning library.

What is the best way to share only the getter methods to client?

I am writing an API with a class like this:
public class NKMPMission {
private String name;
private int age;
public NKMPMission(String name, int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
My Questions:
How can I make sure the user of this NKMPMission class accesses only the getters?
How can I introduce setters for this function so that I as a developer can set, but the user cannot set?
The usual way to do this is to not expose the class at all, just expose interfaces to that class. One interface for the general public and one for developers.
You then need a factory to create them.
/**
* Expose this interface to the public.
*/
public interface INKMPMission {
public String getName();
public int getAge();
}
/**
* Only expose this interface to developers.
*/
interface IDeveloperNKMPMission {
public void setName(String name);
public void setAge(int age);
}
public static class NKMPMissionFactory {
/**
* Expose only the INKMPMission construction.
*/
public INKMPMission make(String name, int age) {
return new NKMPMission(name, age);
}
/**
* Protected version for developers.
*/
IDeveloperNKMPMission forDeveloper(INKMPMission it) {
return IDeveloperNKMPMission.class.cast(it);
}
/**
* Private so no-one outside the factory knows about the inner workings.
*/
private static class NKMPMission implements INKMPMission, IDeveloperNKMPMission {
private String name;
private int age;
private NKMPMission(String name, int age) {
this.name = name;
this.age = age;
}
#Override
public String getName() {
return name;
}
#Override
public int getAge() {
return age;
}
#Override
public void setName(String name) {
this.name = name;
}
#Override
public void setAge(int age) {
this.age = age;
}
}
}
For the truly paranoid you can even use a proxy. This will make it difficult (but not impossible) to use the setters through reflection.
/**
* Expose only the INKMPMission construction.
*/
public INKMPMission make(String name, int age) {
return new NKMPMissionProxy(new NKMPMission(name, age));
}
/**
* Protected version for developers.
*/
protected IDeveloperNKMPMission forDeveloper(INKMPMission it) {
if (it instanceof NKMPMissionProxy) {
it = ((NKMPMissionProxy) it).theMission;
}
return IDeveloperNKMPMission.class.cast(it);
}
/**
* A proxy for the truly paranoid - makes using reflection more difficult (but not impossible)
*/
private static class NKMPMissionProxy implements INKMPMission {
private final NKMPMission theMission;
private NKMPMissionProxy(NKMPMission theMission) {
this.theMission = theMission;
}
#Override
public String getName() {
return theMission.getName();
}
#Override
public int getAge() {
return theMission.getAge();
}
}
1) How can i make sure user of this NKMPMIssion class access only getters.
You can't.
2) How can i introduce setters for this function so that as a developer i should be able to set, but the user should not be able to set.
It sounds like you're writing an API. If you return a NKMPMIssion instance from a public method of that API, the setters can be called. Even if you mark them private or protected, they can still be called via reflection. That said, usually making them non-public is sufficient. It does, at the very least, say "If you call these, you're in unsupported territory."
If you want to make it harder, you can return an instance that wraps a facade around the NKMPMIssion instance. But that just makes it harder, not impossible, since the facade instance has to have a reference to the NKMPMIssion instance, which (even if it's private) can be accessed via reflection.
The easiest thing is to make the API use the interface only and make the class an implementation detail.
public interface INKMPMission {
String getName();
int getAge();
}
public class SomeService{
private class MyNKMPMission implements INKMPMission {
//put getters and setters here
}
public List<INKMPMission> getMissions(){
//put some MyNKMPMissions in a list
}
}
Since MyNKMPMission is private the consumers will never be able do downcast and access the setters.
You can (in some kinda way), but you should not do it that way:
In each setter construct a new Exception
Inspect the generated Stacktrace
If the caller class is not within your package (or hardcode some direct classnames / methodnames) throw an IllegalAccessError
This way is neither pretty, nor fast as you have to check every single access to a setter.
Another way would be using the #CallerSensitive Annotation, though it's propritary API and is therefore not available on all plattforms / jre implementations: https://stackoverflow.com/a/22627383/1164913
The clean, and in most cases sufficent way would be using an Interface which only provides getters to the client, and returning that to the client.
It seems you trying to write an API. Assuming user means, developers who use your API.
In such cases, make the setter as protected and build some meaningful package structure, such that only child's and package members can see that.
If you want to protect that even from child's, there is no way other than making it private.
Answering the questions:
Q1. You can't as T.J. Crowder has said in his answer.
Q2. I would recommend you to try the following things in the following order from easiest to hardest, and take the option you consider the most suitable in terms of effort-return:
Have a look to: Java access modifiers.
Create an interface and expose that interface with the public methods to the "final" users of the "NKMPMission" class, as mentioned in Esben Skov Pedersen answer
Finally you can do the proxy approach mentioned in OldCurmudgeon answer
What I would do:
If your set of classes is going to be used internally then I would take option 1 combined with a good javadoc and project standards, it should be enough.
In case you are creating a public API I would take the option 2.
IMHO the option 3 adds too innecessary complexity in this case, and very few benefit, since every class method or attribute can be accessed anyway throw reflection (as many people has mentioned). I think everybody is aware about the fact that access throw reflection to API's hidden methods is hacky, dangerous and not convenient for the manteinance of the projects, due to API providers are in their right to change hidden methods implementations without further notification to the final users.

Different methods need different attributes in one object

I have a given web service. (This is only an example, the real one is more complex, but it has the same problem.) The service has three methods and all three methods have a person as parameter and need other things from it. (I can't change the entity or methods.)
Entity (Person) (It has only a default constructor):
private String name;
private int age;
private Address address;
private List<String> hobbies;
private List<Person> friends;
Method1 needs name and age.
Method2 needs address name and age.
Method3 needs all.
I need to fill the object from my own objects. I need to write a "converter". What is the best practice for it?
My solutions:
Builder Pattern with builds for three methods.
Set all attributes and send unhandled overhead (bad solution in my eyes).
Creating a builder that sets only required fields sounds good.
You can inherit from this class for each of your needs and implement your own constructors
public class Target {
// fields
}
public class Purpose1 extends Target {
public Purpose1(String name, int age) {
// set fields or do whatever you wish
}
}
public class Purpose2 extends Target {
public Purpose2(String address, String name, int age) {
// set fields or do whatever you wish
}
}
public class Purpose3 extends Target {
public Purpose3(...) {
// set fields or do whatever you wish
}
}
And then you may use instances of subclasses where class Target is required.
I think you can get what you want with a suitable usage of decorator pattern:
https://en.wikipedia.org/wiki/Decorator_pattern

Implementation difference between Aggregation and Composition in Java

I'm aware of the conceptual differences between Aggregation and Composition. Can someone tell me the implementation difference in Java between them with examples?
Composition
final class Car {
private final Engine engine;
Car(EngineSpecs specs) {
engine = new Engine(specs);
}
void move() {
engine.work();
}
}
Aggregation
final class Car {
private Engine engine;
void setEngine(Engine engine) {
this.engine = engine;
}
void move() {
if (engine != null)
engine.work();
}
}
In the case of composition, the Engine is completely encapsulated by the Car. There is no way for the outside world to get a reference to the Engine. The Engine lives and dies with the car. With aggregation, the Car also performs its functions through an Engine, but the Engine is not always an internal part of the Car. Engines may be swapped, or even completely removed. Not only that, but the outside world can still have a reference to the Engine, and tinker with it regardless of whether it's in the Car.
I would use a nice UML example.
Take a university that has 1 to 20 different departments and each department has 1 to 5 professors.
There is a composition link between a University and its' departments.
There is an aggregation link between a department and its' professors.
Composition is just a STRONG aggregation, if the university is destroyed then the departments should also be destroyed. But we shouldn't kill the professors even if their respective departments disappear.
In java :
public class University {
private List<Department> departments;
public void destroy(){
//it's composition, when I destroy a university I also destroy the departments. they cant live outside my university instance
if(departments!=null)
for(Department d : departments) d.destroy();
departments.clean();
departments = null;
}
}
public class Department {
private List<Professor> professors;
private University university;
Department(University univ){
this.university = univ;
//check here univ not null throw whatever depending on your needs
}
public void destroy(){
//It's aggregation here, we just tell the professor they are fired but they can still keep living
for(Professor p:professors)
p.fire(this);
professors.clean();
professors = null;
}
}
public class Professor {
private String name;
private List<Department> attachedDepartments;
public void destroy(){
}
public void fire(Department d){
attachedDepartments.remove(d);
}
}
Something around this.
EDIT: an example as requested
public class Test
{
public static void main(String[] args)
{
University university = new University();
//the department only exists in the university
Department dep = university.createDepartment();
// the professor exists outside the university
Professor prof = new Professor("Raoul");
System.out.println(university.toString());
System.out.println(prof.toString());
dep.assign(prof);
System.out.println(university.toString());
System.out.println(prof.toString());
dep.destroy();
System.out.println(university.toString());
System.out.println(prof.toString());
}
}
University class
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class University {
private List<Department> departments = new ArrayList<>();
public Department createDepartment() {
final Department dep = new Department(this, "Math");
departments.add(dep);
return dep;
}
public void destroy() {
System.out.println("Destroying university");
//it's composition, when I destroy a university I also destroy the departments. they cant live outside my university instance
if (departments != null)
departments.forEach(Department::destroy);
departments = null;
}
#Override
public String toString() {
return "University{\n" +
"departments=\n" + departments.stream().map(Department::toString).collect(Collectors.joining("\n")) +
"\n}";
}
}
Department class
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Department {
private final String name;
private List<Professor> professors = new ArrayList<>();
private final University university;
public Department(University univ, String name) {
this.university = univ;
this.name = name;
//check here univ not null throw whatever depending on your needs
}
public void assign(Professor p) {
//maybe use a Set here
System.out.println("Department hiring " + p.getName());
professors.add(p);
p.join(this);
}
public void fire(Professor p) {
//maybe use a Set here
System.out.println("Department firing " + p.getName());
professors.remove(p);
p.quit(this);
}
public void destroy() {
//It's aggregation here, we just tell the professor they are fired but they can still keep living
System.out.println("Destroying department");
professors.forEach(professor -> professor.quit(this));
professors = null;
}
#Override
public String toString() {
return professors == null
? "Department " + name + " doesn't exists anymore"
: "Department " + name + "{\n" +
"professors=" + professors.stream().map(Professor::toString).collect(Collectors.joining("\n")) +
"\n}";
}
}
Professor class
import java.util.ArrayList;
import java.util.List;
public class Professor {
private final String name;
private final List<Department> attachedDepartments = new ArrayList<>();
public Professor(String name) {
this.name = name;
}
public void destroy() {
}
public void join(Department d) {
attachedDepartments.add(d);
}
public void quit(Department d) {
attachedDepartments.remove(d);
}
public String getName() {
return name;
}
#Override
public String toString() {
return "Professor " + name + " working for " + attachedDepartments.size() + " department(s)\n";
}
}
The implementation is debatable as it depends on how you need to handle creation, hiring deletion etc. Unrelevant for the OP
A simple Composition program
public class Person {
private double salary;
private String name;
private Birthday bday;
public Person(int y,int m,int d,String name){
bday=new Birthday(y, m, d);
this.name=name;
}
public double getSalary() {
return salary;
}
public String getName() {
return name;
}
public Birthday getBday() {
return bday;
}
///////////////////////////////inner class///////////////////////
private class Birthday{
int year,month,day;
public Birthday(int y,int m,int d){
year=y;
month=m;
day=d;
}
public String toString(){
return String.format("%s-%s-%s", year,month,day);
}
}
//////////////////////////////////////////////////////////////////
}
public class CompositionTst {
public static void main(String[] args) {
// TODO code application logic here
Person person=new Person(2001, 11, 29, "Thilina");
System.out.println("Name : "+person.getName());
System.out.println("Birthday : "+person.getBday());
//The below object cannot be created. A bithday cannot exixts without a Person
//Birthday bday=new Birthday(1988,11,10);
}
}
In simple terms :
Both Composition and Aggregation are Associations.
Composition -> Strong Has-A relationship
Aggregation -> Weak Has-A relationship.
There is a great explanation in the given url below.
http://www.codeproject.com/Articles/330447/Understanding-Association-Aggregation-and-Composit
Please check!!!
First we must talk about what actually the difference between Aggregation and Composition is to be on the same page.
Aggregation is an association where the associated entity may exist independent of the association. For example, a Person may be associated to an Organisation but he/she may have independent existence in the system.
whereas
Composition refers to a situation when one of the associated entities is strongly related to the other and cannot exist without the other's existence. In fact the identity of that entity is always associated with the identity of the other object. For example, wheels in a car.
Now, aggregation can simply be achieved by holding a property of one entity in another as below:
class Person {
Organisation worksFor;
}
class Organisation {
String name;
}
class Main {
public static void main(String args[]) {
//Create Person object independently
Person p = new Person();
//Create the Organisation independently
Organisation o = new Organisation();
o.name = "XYZ Corporation";
/*
At this point both person and organisation
exist without any association
*/
p.worksFor = o;
}
}
For Composition it is necessary that the dependent object is always created with the identity of its associated object. You can use an inner class for the same.
class Car {
class Wheel {
Car associatedWith;
}
}
class Main {
public static void main() {
//Create Car object independently
Car car = new Car();
//Cannot create Wheel instance independently
//need a reference of a Car for the same.
Car.Wheel wheel = car.new Wheel();
}
}
Please note that the same use case may fall under aggregation/composition depending on the application scenario. For example, the Person-Organisation case may become composition if you are developing an application for people working in some organisation and the reference to organisation is must for sign up. Similarly, if you are maintaining inventory for parts of a Car, Car-Wheel relationship can be aggregation.
The difference is that any composition is an aggregation and not vice versa.
Let's set the terms. The Aggregation is a metaterm in the UML standard, and means BOTH composition and shared aggregation, simply named shared. Too often it is named incorrectly "aggregation". It is BAD, for composition is an aggregation, too. As I understand, you mean "shared".
Further from UML standard:
composite - Indicates that the property is aggregated compositely,
i.e., the composite object has responsibility for the existence and
storage of the composed objects (parts).
So, University to cathedras association is a composition, because cathedra doesn't exist out of University (IMHO)
Precise semantics of shared aggregation varies by application area and
modeler.
I.e., all other associations can be drawn as shared aggregations, if you are only following to some principles of yours or of somebody else. Also look here.
Aggregation vs Composition
Aggregation implies a relationship where the child can exist independently of the parent. For example, Bank and Employee, delete the Bank and the Employee still exist.
whereas Composition implies a relationship where the child cannot exist independent of the parent. Example: Human and heart, heart don’t exist separate to a Human.
Aggregation relation is “has-a” and composition is “part-of” relation.
Composition is a strong Association whereas Aggregation is a weak Association.
Both types are of course associations, and not really mapped strictly to language elements like that. The difference is in the purpose, context, and how the system is modeled.
As a practical example, compare two different types of systems with similar entities:
A car registration system that primarily keep track of cars, and their owners, etc. Here we are not interested in the engine as a separate entity, but we may still have engine related attributes, like power, and type of fuel. Here the Engine may be a composite part of the car entity.
A car service shop management system that manages car parts, servicing cars, and replace parts, maybe complete engines. Here we may even have engines stocked and need to keep track of them and other parts separately and independent of the cars. Here the Engine may be an aggregated part of the car entity.
How you implement this in your language is of minor concern since at that level things like readability is much more important.

Categories

Resources