I am trying to build a UML class model for an android game that I have developed. I'm finding it difficult to understand the difference between objects, attributes and operations. Any suggestions?
Objects are instances of classes, so think in terms of classes, attributes and operations.
Classes map directly to the UML class.
Attributes are fields or properties of the class.
Operations are logic exposed as methods. Do not include getters and setters here - they're essentially a work-around for the lack of true properties in Java, and so are already covered in the attributes section.
public class Person {
private final String name;
private final int age;
public Person(String name,
int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String toString() {
return "Person " + name + " is " + age + " years old";
}
}
In UML, this would translate to
Class Person
Attributes name, age
Operations toString
Examples:
Object: Dog, Table, Human, Car ...
Attributes (properties): Arms, Legs, Tires ...
Operations (methods): drive(), bark(), eat(), sleep() ...
Buy a good book to understand the basics of OOP.
Related
I repeatedly saw code like the following, where the empty constructor was deleted by well-intentioned developers (because it appeared unused), which then broke Jackson serialization (caught by tests later on):
public class Person {
private String name;
private int age;
// appears unused – only used by Jackson
public Person() {}
// used in code
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
I'm thinking of adding a #JsonCreator annotation to the empty constructor to make it more obvious that the constructor is used by Jackson to prevent developers from removing it:
public class Person {
private String name;
private int age;
#JsonCreator // <--------
public Person() {}
// used in code
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
Is this a good idea or does this have unintended consequences (i. e. changing semantics compared to the no-annotation case)?
Or is this use of #JsonCreator an anti-pattern and there is a better way to achieve this (short of converting the class to a record)?
Reading more documentation about this I and regarding all the comments to the question and other answer(s) I came to the conclusion that it really is an anti-pattern to use the #JsonCreator for the default constructor.
The Javadoc (e.g. from version 2.13) specifies that a ctor annotated with that annotation should have at least one parameter. (It doesn't explicitly say so, but a ctor without arguments would be useless more or less.)
NOTE: when annotating creator methods (constructors, factory methods), method must either be:
Single-argument constructor/factory method without JsonProperty annotation for the argument: if so, this is so-called "delegate creator", in which case Jackson first binds JSON into type of the argument, and then calls creator. This is often used in conjunction with JsonValue (used for serialization).
Constructor/factory method where every argument is annotated with either JsonProperty or JacksonInject, to indicate name of property to bind to
So for your problem I would suggest that you get rid of the default ctor and instead annotate at least one of the remaining ctor(s) used in code as well properly. Jackson can use that and the IDE will not mark it as unused.
It also could save you from workarounds for not properly or completely initialized objects.
In your example this could be
public class Person {
private String name;
private int age;
#JsonCreator
public Person(#JsonProperty("name") String name, #JsonProperty("age") int age) {
this.name = name;
this.age = age;
}
// other getters / setters / business logic come here
}
It's an anti pattern, because the default constructor is the #JsonCreator default and everyone knows it - it is useless code.
You don't need to prevent developers from removing it because your functional tests will fail if they do so.
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 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;
}
See below code for example:
public enum Employees {
BOB("Bob Barker", "BB", 100);
private String fullName; //are these better accessed through public or getFullName() below?
private String initials;
private String age;
Employees(String fullName, String initials, int age) {
this.fullName = fullName;
this.initials = initials;
this.age = age;
}
public String getFullName() {
return fullName;
}
//etc ...
}
Which method of accessing more correct or more memory efficient?
You cannot access the fullName through a static method. They are instance fields.
Your code is correct. You may wish to mark your String fields as final and rid yourself of the setXXX methods (since Enum values are traditionally immutable).
I would always make enum fields final, which then removes the utility of a setter. The enum instance is publicly shared and it is expected to be immutable by most sensible client code.
As far as the getter is concerned, that's up to your personal taste, although convention has it to add a getter and make the field private. So your taste has to be "strong".
use a getter its the convention ... and you won't get any nasty surprises if you at a later date use the enum within jstl/el which relies on the bean specification of using getters/is.
I think you are misunderstanding the concept of enums. An enum is a shared instance that does not change. What you describe is a regular mutable Java object. So the first thing you should do is switch from enum to class:
public class Employee {
private String fullName;
private String initials;
private String age;
public Employee(String fullName, String initials, int age) {
this.fullName = fullName;
this.initials = initials;
this.age = age;
}
public String getFullName() {
return fullName;
}
//etc ...
}
Then use your class like a regular class:
Employee bob = new Employee("Bob Barker", "BB", 100);
Edit
You have removed your setter now, but still, this still does not look like an enum to me.