Hello, I'm trying to to convert this UML diagram to java code directly, and below is my code which doesn't seem to compile anyways. I'm not very sure about how to place the optional multiplicities in, e.g. 0..* and 0..1. Thank you for your help.
public class Person{
private String name;
private Person mom;
private Person dad;
private ArrayList<Person> child;
private ArrayList<Person> friend;
private ArrayList<School> alumni;
private School current = new School();
public Person(String name, Person mom, Person dad, ArrayList<Person> child, ArrayList<Person> friend, ArrayList<School> alumi, School current){
name = this.name;
mom = this.mom;
dad = this.dad;
child = this.child;
friend = this.friend;
alumni = this.alumni;
current = this.current;
}
}
public class School{
private String name;
private ArrayList<Person> student;
public School(String name, ArrayList<Person> student){
name = this.name;
student = this.student;
}
}
There is no standardized way of converting UML to Java, but I can tell you what is correct and not correct based on the UML and Java semantics.
An association between classes C1 and C2 may be implemented by a property in class C1, or by a property in class C2 or by properties in both classes. If an association does not have an arrowhead, all three options are possible and it is not defined which of these three options is the best. If an association is an arrow pointing from C1 to C2, then the first option is the best, the second option is incorrect and the third option is allowed. I have checked your Java code and it complies to these rules.
If class C1 has a property P implementing an association between class C1 and class C2 and the association has a multiplicity of 0..1 at the side of C2, then P should have type C2 and C1 should have a constructor that does not initialize P. Your Java code is incorrect, because you should not initialize Person.School.
If the multiplicity is * or 0..*, then P should be some kind of collection of C2. Class C1 should have a constructor that either does not initialize P or that can initialize P with an empty collection. The latter is the case in your Java code.
public class Person{
private String name;
private Person mom;
private Person dad;
private ArrayList<Person> child;
private ArrayList<Person> friend;
private ArrayList<School> alumni;
private School current = new School();
This part seems correct except for the School which should be null as the person might not be studying at the moment.
private School current;
keyword this (see Using the this Keyword) refers to current object in Java so the constructor should be written as
public Person(String name, Person mom, Person dad, ArrayList<Person> child, ArrayList<Person> friend, ArrayList<School> alumi, School current){
this.name = name;
this.mom = mom;
...
}
same problem with the School class:
public class School{
private String name;
private ArrayList<Person> student;
public School(String name, ArrayList<Person> student){
this.name = name;
this.student = student;
}
}
if you are defining both classes in the same file you have to remove public from the class definition of School, which becomes then
class School{
or move to a file called School.java see oracle.com/javase/tutorial/java/javaOO/nested.html
Related
Forgive me if this is a duplicated question but I'm a beginner in Java and I'm currently trying to get the parameter value from a class called Name and pass that value into another class called Student.
Name Class:
public class Name
{
public String studentName;
public Name(String fullName)
{
studentName = fullName;
}
}
Student Class:
public class Student
{
private Name studentName;
private String id;
private int credits;
public Student(String studentID)
{
studentName = new Name("");
id = studentID;
credits = 0;
}
}
What I want to do is to get the parameter value of fullName which is set in the Name class and pass it in studentName = new Name(""); for the Student class instead passing in an empty string to retrieve the name.
What do you mean by "taking the parameter value of fullName, which is set in Name class"? A class will not have a value, you need access to the instance of this class. I'm pretty sure you will have some kind of control class, e.g. where your main() resides.
At some point you will have created a Name instance:
Name n = new Name("Brandon");
Using this instance of Name class, you can access the actual value:
Student s = new Student("4711", n.studentName);
, assuming you also have included an additional parameter in your Student constructor:
public class Student
{
private Name studentName;
private String id;
private int credits;
public Student(String studentID, String name)
{
studentName = new Name(name);
id = studentID;
credits = 0;
}
}
, but this would result in you having 2 different Name objects.
Another option is to pass the object itself as parameter, so both of your objects reference to same object. Changing studentName of either n.studentName and s.studentName would in theoretically result in the value of the respective other being changed as well (I can recall some discussions regarding that topic in Java though).
public class Student
{
private Name studentName;
private String id;
private int credits;
public Student(String studentID, Name nameObject)
{
studentName = nameObject;
id = studentID;
credits = 0;
}
}
, which is instantiated by
Name n = new Name("Brandon");
Student s = new Student("4711", n);
You should definitely start reading introductions into object oriented programming, as there are quite a lot of misassumptions just in those few lines of code. The difference between class and object is crucial, also it's usual in those scenarios to have getters/setters rather than public variables in classes. To achieve the kind of dependency you want to have, you might want to look into composition and aggregation in the context of object-orientation. Also the difference between pass-by-value and pass-by-reference is worth looking into.
I'm using Neo4j ogm to map many (over 20) similar classes into neo4j db which are different in just
relationship name, name and direction.
Each class implements the "Classification" interface with just one method which is the same
in every class (consist on adding relation into collection of node)
Example node:
#NodeEntity
public class ExampleClass implements Classification {
#GraphId
private Long id;
private String name;
#Relationship(type = "EXAMPLE_1", direction = "OUTGOING")
private Set<Species> classification = new HashSet<>();
public ExampleClass (){}
public ExampleClass (String name) {
this.name = name;
}
public Set<Species> getClassification(){
return classification;
}
#Override
public void specifiedAs(Species species){
classification.add(species);
}
and analogously:
#NodeEntity
public class ExampleClass2 implements Classification {
#GraphId
private Long id;
private String name;
#Relationship(type = "EXAMPLE_2", direction = "OUTGOING")
private Set<Species> classification = new HashSet<>();
public ExampleClass2 (){}
public ExampleClass2 (String name) {
this.name = name;
}
public Set<Species> getClassification(){
return classification;
}
#Override
public void specifiedAs(Species species){
classification.add(species);
}
}
I'm looking for possibility to reduce count of those similar classes
and create... maybe one generic class in which I can define label,property name and realtionship type also.
I prefer still using spring-data and Neo4j OGM.
You could improve this by introducing an super class containing all the common properties, and just have the specific relationships in your ExampleClassXXX classes.
Note that the relationship types cannot be dynamic, so you cannot have just a generic class by itself.
I have two classes:
public class1{
private int id;
private List<Student> students;
}
public Student{
private name;
private address;
}
public Class2{
private int id;
private List<Person> person;
}
public Person{
private personName;
private location;
}
I have to map/copy values from class1 to class2. I tried to use dozer bean mapper API, but I could not map List of Student with List of Person as they have different field names but same function. Please help me with dozer mapping or if there is other solution, highly appreciated.
Thanks!
Try something like this:
public static List<Person> mapValues() {
List<Student> students = class1.getStudents(); // Assuming you have getters of students field
List<Person> persons = class2.getPersons(); // Assuming you have getters of persons field
for(Student student: students) {
Person person = new Person();
person.setPersonName(student.getName);
person.setLocation(student.getAddress);
persons.add(person);
}
return persons;
}
I have two immutable classes: User and Department, they are connected using a bidirectional association - User has a reference to Department and Department has a list of Users. How to create a new Department instance with the provided Users?
Code:
class User {
private final Department department;
private final String name;
public User(Department department, String name) {
this.department = department;
this.name = name;
}
}
class Department {
private final List<User> users;
private final String name;
public Department(List<User> users, String name) {
this.users = new ArrayList<>(users);
this.name = name;
}
}
I feel in you case you can slightly modify your design and use special UsersBuilder, i.e.
class Department {
final List<User> users;
final String name;
public Department(String name) {
this.users = UsersBuilder.buildUsers(this);
this.name = name;
}
}
class UsersBuilder {
public static List<User> buildUsers(Department department) {
List<User> usersList = new ArrayList<>();
// add users to the list via department reference
return Collections.unmodifiableList(usersList);
}
}
In general, it is not really good idea to use object's reference before its constructor finishes; but in this particular case it looks safe.
In this case these objects will be really immutable.
You can produce immutable Departments and Users with an extra constructor on Department. From the questions' code, it is inferred that
A User object is just an association between a String and a Department
User references can't exist without a Department reference.
Since Users are truly just Strings associated to a Department, a Department can be constructed with a List<String> that represents all User names to be included and use that List<String> to create a List<User> within the Department constructor.
Note: what #andremoniy said about letting this escape from a constructor should not be made a habit of, but it is safe in this case since it is only being passed to a User instance's constructor where that User instance can't be accessed before the Department constructor returns.
Here's what it would look like, in Java 8:
public final class User {
private final Department department;
private final String name;
public User(Department department, String name) {
this.department = department;
this.name = name;
}
public Department getDepartment() {
return department;
}
public String getName() {
return name;
}
}
public final class Department {
private final List<User> users;
private final String name;
///Reversed argument list to avoid collision after erasure
public Department(String name, List<String> users) {
this.users = Collections.unmodifiableList(users.stream()
.map((s) -> new User(this,s)).collect(Collectors.toList()));
this.name = name;
}
public Department(List<User> users, String name) {
this.users = Collections.unmodifiableList(users);
this.name = name;
}
public List<User> getUsers() {
return users;
}
public String getName() {
return name;
}
}
One issue this solution has is that once a Department instance is created, it can be added to new instances of User without the constraint that a new instance of Department be created with an updated List. Consider other abstractions or creational patterns (a full blown Builder implementation where all constructors are private would be a good match here) if you need to support the addition/deletion of users from a Department while maintaining immutability.
Instantiate Department with empty list of users. Then use the Department to instantiate User and add the user instance to the Department's users list.
One approach is to slightly alter what you understand immutable to mean. In object oriented design it is conventional to distinguish between the attributes of an object and its associations. Associated objects are different entities to which the object has references. If you relax the definition of immutable to mean that the attributes of the object do not change, but allow the associations to change, you avoid this kind of problem.
In your case, User and Department objects would be associated with each other, and each would have a name attribute.
I think this is a matter of modeling as well. This is ok to think that an User has a Department and a Department have Users, but the question is how deep can you look into data from User and Department ends?
Does it make sense unless conceptually you to access user.department.user[2].name? What about department.user[10].addresses[1].street?
I really don't think so on most scenarios. It's a matter of information domain. You have bondaries while accessing data and this can also be expressed somehow into your models.
If Object Modeling kind represents the real world, this is ok to think that when you go to a department, you will see dozens of people working there and most likely all you will be able to know about them is the counting and the their names perhaps. So what slices of data you should be able to see from your object?
My approach for this is:
interface PersonInfo {
String name();
String lastName();
default fullName() { return name() + " " + lastName(); }
static PersonInfoBuilder personInfo() { return new PersonInfoBuilder(); }
static class PersonInfoBuilder {
...
}
}
interface Person extends PersonInfo {
DepartmentInfo department();
Set<Address> addresses();
//...
}
interface DepartmentInfo {
String name();
String building();
// builder ...
}
interface Department extends DepartmentInfo {
Set<PersonInfo> employees();
// ...
}
I don't think i'd need to show how the builders would work since if you noticed, for this scenario, the bidirectional nature of relationship is never there. So when you build a Person, all you need is the DepartmentInfo (department no employees not required), and the same is valid when you build a Department, when all you need to have is the PersonInfo from department's employees.
That's my way to think this problem conceptually. Any comments?
My solution is to: split one of the immutable classes into two classes: a class with the attributes and a class with the bidirectional association:
class Department {
private final String name;
public Department(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class User {
private final Department department;
private final String name;
public User(Department department, String name) {
this.department = department;
this.name = name;
}
}
class DepartmentWithUsers {
private final List<User> users;
private final Department department;
public DepartmentWithUsers(Department department, List<User> users) {
this.department = department;
this.users = new ArrayList<>(users);
}
}
So to create a new user and a department instance you have to:
create a new Department instance
create a new User instance and pass the created Department instance
create a new DepartmentWithUsers instance and pass the created User instance
I have two classes Person and Company, where the associations specify like:
(1) person work for a company
(2) person(boss) manages person(worker) by rating.
Details is provided in this image:
In case of first association i did this:
class Person {
Company co;
String name, ssn, addr;
}
class Company {
String name, addr;
}
class WorksFor {
Person person;
Company com;
int sal;
String title;
}
Is it correct implementation? also i am confused about second association. Please help me with your valuable advise.
It is not.
You should know that if class have associetion with something it is like it has attribute that type with given cardinality.
So for example Person would have given fields (omitting association classes):
String name[1]
String ssn[1]
String addr[1]
Company company[1]
Person boss[0..*]
Person worker[1..*]
Then how to change those to java:
String name;
String ssn;
String addr;
Company company;
List<Person> bosses;
List<Person> worker;
But remember if there is required number of given type you should pass those elements in constructor.
One thing important to mention: if in UML value is omitted it means [1].
So we need to have constructor that takes worker as argument.
With association classes things getting more complicated:
You should create classeslike
class Performance {
Person boss;
Person worker;
int performanceRating;
public Performance(Person boss, Person worker, int performanceRating){
this.boss = boss;
this.worker = worker;
this.performanceRating = performanceRating;
}
}
And in person change those list of Persons to list of Performance.
Still it's invalid UML diagram so I'm not perfectly sure if my answer can helps.
Usually, class in model (classes associated with data) is related with real-world objects. And it is common practice to call classes with a noun, so I would change WorksFor into something else.
class Person {
String name, ssn, addr;
Job job;
Person boss;
}
class Company {
String name, addr;
}
class Job {
Company co;
int salary;
String title;
}
The problem with code above is ratings and obtaining workers of the boss - it can be solved in multiple ways. Assuming, that every boss is also a worker, you can extend a Person class:
class Boss extends Person {
List<Person> workers;
}
Another possibility is keeping list of workers with Person - list will be empty/null if a person is not a boss.
Some ideas of performance management is given in KonradOliwer answer, I'm not going to duplicate it.
Could do like this:
class Person {
EmploymentRelationship employmentRelationship;
List<ManagementRelationship> workerManagementRelationships;
ManagementRelationship bossManagementRelationship;
String name, ssn, addr;
}
class Company {
String name, addr;
}
class EmploymentRelationship {
Person person;
Company com;
int sal;
String title;
}
class ManagementRelationship {
int performanceRating;
Person boss;
Person worker;
}