A have a question related to creating object list in Java class.
Can someone tell me which solution is better? Pros and cons of it?
1) My first version of class:
public class ProductRepositoryImpl implements ProductRepository {
private List<Product> listOfProducts = new ArrayList<Product>();
public ProductRepositoryImpl() {
addProducts(1, "Silnik", "Ferrari", 1000, listOfProducts);
addProducts(2, "Sprzęgło", "Opel", 500, listOfProducts);
addProducts(3, "Kierownica", "Fiat", 100, listOfProducts);
addProducts(4, "Panewka", "Maluch", 250.00, listOfProducts);
addProducts(5, "Akumulator", "Autosan", 1700.00, listOfProducts);
addProducts(6, "Zakrętka", "Maseratii", 100.00, listOfProducts);
}
private void addProducts(int idProduct, String name, String brand, double price, List list) {
Product product = new Product();
product.setId(idProduct);
product.setName(name);
product.setBrand(brand);
product.setPrice(price);
list.add(product);
}
#Override
public List<Product> getListOfProducts() {
return listOfProducts;
}
}
2) And the second one:
public class ProductRepositoryImpl implements ProductRepository {
private List<Product> listOfProducts = new ArrayList<Product>();
public ProductRepositoryImpl() {
Product p1 = new Product();
p1.setId(1);
p1.setName("Silnik");
p1.setBrand("Ferrari");
p1.setPrice(1000);
Product p2 = new Product();
p2.setId(2);
p2.setName("Hamulec");
p2.setBrand("Opel");
p2.setPrice(500);
Product p3 = new Product();
p3.setId(3);
p3.setName("Kierownica");
p3.setBrand("Fiat");
p3.setPrice(100);
Product p4 = new Product();
p4.setId(4);
p4.setName("Akumulator");
p4.setBrand("Autosan");
p4.setPrice(1700);
Product p5 = new Product();
p5.setId(5);
p5.setName("Zakrętka");
p5.setBrand("Maseratii");
p5.setPrice(100);
listOfProducts.add(p1);
listOfProducts.add(p2);
listOfProducts.add(p3);
listOfProducts.add(p4);
listOfProducts.add(p5);
}
#Override
public List<Product> getListOfProducts() {
return listOfProducts;
}
}
I will be grateful for every explaination.
There are some design guide lines which will help you in improving your code :
Separation of responsibilities. ProductRepositoryImpl should be responsible for dealing with a repository of products. It is not its responsibility and should not have code for constructing Products. Construction of products should be the responsibility of Product
Code reuse. Version 1 is better than version 2 since the code for construction of a product is written once, inside addProducts(), rather than multiple times as in version 2.
Encapsulation. The interface of a class is the only part which should be public. It's implementation should be hidden. This means that the id field of a product should not be directly accesed from the outside, but instead should be accesed through interface methods. The advantage being that if you later on need to change how ids internally work you can do it easily because all ids come and go from a few methods in the Product class. If the id field is public then there may be hundreds of places accessing it and dealing with such a change would be a nightmare.
Another issue is mutability. Your Product class is mutable, as implied by the setName method. If that is an absolute requirement of your application go ahead. But if a product does not change once defined you should rather make Product inmutable. Inmutability has several advantages, one of them being that it is thread safe without needing synchronization. So I have made Product inmutable.
With those guide lines in mind this is the approach I would take :
class Product
{
private final int idProduct;
private final String name;
private final String brand;
private final double price;
public Product(int idProduct, String name, String brand, double price)
{
this.idProduct = idProduct;
this.name = name;
this.brand = brand;
this.price = price;
}
}
public class ProductRepositoryImpl implements ProductRepository
{
private List<Product> listOfProducts = new ArrayList<Product>();
public ProductRepositoryImpl()
{
addProduct(new Product(1, "Silnik", "Ferrari", 1000));
addProduct(new Product(2, "Sprzęgło", "Opel", 500));
addProduct(new Product(3, "Kierownica", "Fiat", 100));
addProduct(new Product(4, "Panewka", "Maluch", 250.00));
addProduct(new Product(5, "Akumulator", "Autosan", 1700.00));
addProduct(new Product(6, "Zakrętka", "Maseratii", 100.00));
}
private void addProduct(Product product)
{
listOfProducts.add(product);
}
#Override
public List<Product> getListOfProducts()
{
return listOfProducts;
}
}
The first option denotes a Factory and is usually recommended.
The reason why it is recommended is because object initialization is localized to one central place, thus if you need to perform any extra checks before the initialization, such design would ensure that you need only make changes to one portion of the code.
As a side note, in the example you posted, it woon't really make much of a difference since should the structure of the object change, you would only need to add an extra setter instead of passing an extra parameter.
However, in other scenarios object creation would depend on other objects. Thus, the pattern would allow you to make the least amount of changes, thus reducing the chances of introducing new bugs in the code because you forgot to update that one line burried somewhere in your code.
Also as it has been pointed out in the comments, addProducts should really become addProduct, since it is adding only one item.
In general the first design is better. It reduces code duplication. On the other hand you can improve it further.
It seems that your object stores only hardcoded values. You should consider moving this code into .property files
Returning immutable version of your list. It might prevent some unpleasant surprises
If you want to perceive this object as a true repository you should provide method which will have some fetching method by specification/filter. Currently it does not provide encapsulation.
Related
Let's say in a simple shopping application there are a Customer class, Seller class, and Trade class, and the code looks simply like this(to illustrate my question):
public class HelloWord {
public static void main(String[] args) {
Customer customer = new Customer();
Seller seller = new Seller();
Trade trade = new Trade(customer,seller);
trade.buy(2);
}
}
class Customer {
private ArrayList<String> itemCart = new ArrayList<String>();
private int gold = 100;
public void setGold(int amount) {
if (gold - amount >= 0) {
gold -= amount;
}
}
public int getGold() {
return gold;
}
public void add(String item) {
itemCart.add(item);
}
}
class Seller {
private ArrayList<String> itemCart = new ArrayList<String>();
private ArrayList<Integer> itemsPrice = new ArrayList<Integer>();
public int getItemPrice(int itemID) {
return itemsPrice.get(itemID);
}
public String getItemById(int itemID) {
return itemCart.get(itemID);
}
}
class Trade {
private Customer customer;
private Seller seller;
public Trade(Customer customer, Seller seller) {
this.customer = customer;
this.seller = seller;
}
public void buy(int itemID) {
if (seller.getItemPrice(itemID) <= customer.getGold()) {
customer.add(seller.getItemById(itemID));
customer.setGold(seller.getItemPrice(itemID));
} else {
System.out.println("You don't have enough money to buy this item");
}
}
}
My question is "Do the "setGold" and "add" methods expose the attruputs?" i don't want the user to be able to modify the itemCart neither the gold attribute by just call the add method or setGold on his own, but i want to be able to access them to modify the attruputs using other methods, in this case from "buy" method in Trade class.
My question in other words: "Should i be concerned if these method could be accessed from the main method or that is normal and does not violate data integrity?"
You are not getting the answer you expect because the question is a bit confusing as it is now. Reading through it carefully, you are not asking if the main method can access/change the Customer properties directly, but if the main method can use the add and setGold methods to change those properties. Also, the Seller class is just adding entropy as it's not relevant for the question.
Breaking it down:
Do the "setGold" and "add" methods expose the attruputs?
The attributes themselves are not exposed but both methods allow modifying those attributes from the outside since they are declared as public.
i don't want the user to be able to modify the itemCart neither the gold attribute buy just call the add method or set gold on his own
This is possible with your current code as both add and setGold are public. That's exactly the purpose of public.
but i want to be able to access them to modify them using other methods, in this case from "buy" method in Trade class
If you want add and setGold to be visible only to the Trade class, one option is to put Trade and Customer classes in the same package as in the following example:
com.example
shopping
|--- Customer.java
|--- Trade.java
application
|--- HelloWorld.java
And then make both methods package-private, like so:
public Customer {
// ... properties and other methods
void setGold(int amount) {
if (gold - amount >= 0) {
gold -= amount;
}
}
void add(String item) {
itemCart.add(item);
}
}
The difference to your code is that neither method contains a visibility modifier (removed the public keyword), making them package-private, thus only accessible from the same package.
With that structure and package-private methods in the Customer class, if you call the add or setGold from the main class you will get a compiler error:
add(java.lang.String) is not public in com.example.shopping.Customer;
cannot be accessed from outside package
But you can still access it from the Trade class because it's in the same package.
Short ans no, since itemCart is private, runtime caller can't access that directly.
Long answer https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html.
The purpose of data encapsulation is to hide the implementation of an object by ensuring that the contents of the object are only modifiable through the interface of the object. By that definition - the Trade object inherently breaks encapsulation because of its constructor. Since you are passing in references to Customer and Seller, any invariants that the Trade object is supposed to maintain can be broken simply by the person modifying the customer or seller directly.
It's hard to know what the best alternative is without more context, but a possible fix could be rather than passing in the Customer and Seller on construction of the Trade object, passing them into the buy function. Another solution could be to attach the buy function to the Customer or Seller objects instead, getting rid of the Trade object altogether. Generally classes in OOP represent objects, and not actions (outside of certain design patterns).
The setter itself doesn't expose anything. So long as you're not exposing the exact fields (e.g. you're not doing getItemsPrice and returning an ArrayList), you're fine.
All bets are off with reflection, however. But, that's not the concern here.
I suggest you should change the setter to common form, and you can make it private.
private void set(int amount) {
this.amount = amount;
}
public boolean spend(int amount) {
if (gold - amount >= 0) {
gold -= amount;
return true;
} else {
return false;
}
}
In buy method, invoke spend().
I have the following case here:
Room { price; }
|
------
/ \
standard suite
I want to set price the of standard rooms in such a way that it remains static in all instances of standard and must not affect suite's price and vice versa. I have tried keeping price in Room class static and accessing it via getter and setter in child classes but it doesn't work. I also am reluctant to make price members in each child class because I don't like that solution. Maybe there's another beautiful OOP solution to it.
Having a separate static field in both the Room and Suite classes is the quickest/easiest solution.
Room
_________|_______
/ \
Standard Suite
| |
`static int price; `static int price;
Alternatively, you could create a static Map<Class<? extends Room>, Integer> in the Room class which stores the base price of each Room type.
public class Room {
private static Map<Class<? extends Room>, Integer> prices =
new HashMap<>();
public final int getRoomBasePrice() {
// If a Room subclass does not have a specific base price, return
// 1000 by default.
return Room.prices.getOrDefault(this.getClass(), 1000);
}
/** Sets the base price for the specified Room type.
*/
public final void setRoomBasePrice(int price) {
Room.prices.put(this.getClass(), price);
}
}
Using the above code will ensure the price stays constant across all instances of the class.
mySuite.setRoomBasePrice(2000);
(new Suite()).getRoomBasePrice(); // -> 2000
EDIT: After reconsideration, I realise that using static is not the correct method to solve the problem as it makes the code brittle and difficult to change.
The best method would be to have a separate RoomPriceService class, which provides a lookup for obtaining the price of a specific room type.
public class RoomPriceService {
private Map<Class<? extends RoomType>, Integer> prices;
public RoomPriceService(int defaultPrice) {
this.prices = new HashMap();
}
public void setPriceOfRoomType(Room r, Integer price) {
this.prices.set(r.getClass(), price);
}
public Integer getPriceOfRoomType(Room r) {
// You can expand on this code by adding setters/getters for
// setting and getting the default room price.
return this.prices.getOrDefault(r.getClass(), 100);
}
}
This way, you can have multiple RoomPriceService instances which can store prices for different circumstances (for example, you could have a RoomPriceService for each season, or a RoomPriceService for different sale promotions, etc).
I was reading about Spring and encountered an example consisting of an abstract product class with name and price fields.
Next, there is a Battery class which extends the Product class and adds a rechargable field. Then, a CDDrive class (also) extending Product but adding a capacity field.
In the real world when we often have products having many disparate attributes, how does one model arbitrary products with arbitrary properties and fields?
Does having a class for each product make sense?
So, can you guys please suggest a pattern for achieving this?
Thanks,
Ouney
Good question. We had a similar situation before where we had GUI components that shared many of their abstract parent, but each page had its own set of labels that weren't shared by others. The standoff was on. We found it silly to just keep creating subclasses because of the mutually disjoint properties they had. What did it for us was maps. First, to have a subclass is to have one or more distinguishing properties that are fist class objects. Rechargeable for batteries and capacity for cd drives in your case. Then for the properties one can't think of at the time of building, or simply differ in minor naming conventions, use maps. I demonstrate with the example below.
The product:
public abstract class Product {
String name;
Double price;
Map<String, Object> propMap;
public Product(String name, Double price) {
this.name = name;
this.price = price;
propMap = new HashMap<>();
}
public void add2propMap(String key, Object value) {
propMap.put(key, value);
}
public String toString() {
return "Product [name=" + name + ", price=" + price + ", propMap=" + propMap + "]";
}
}
The CdDrive:
public class CdDrive extends Product {
String capacity;
public CdDrive(String name, Double price, String capacity) {
super(name, price);
this.capacity = capacity;
}
}
The Battery:
public class Battery extends Product {
Boolean rechargable;
public Battery(String name, Double price, Boolean rechargable) {
super(name, price);
this.rechargable = rechargable;
}
}
Then a client:
public class Client {
public static void main(String[] args) {
List<Product> productList = new ArrayList<>();
Battery energizer = new Battery("Energizer", 12d, true);
energizer.add2propMap("numInPackage", new Integer(8));
energizer.add2propMap("make", "US");
productList.add(energizer);
CdDrive superDrive = new CdDrive("Apple Drive", 200d, "200 GB");
superDrive.add2propMap("type", "External");
superDrive.add2propMap("expandable", false);
productList.add(superDrive);
productList.forEach(p -> System.out.println(p));
}
}
Which gives this when run:
Product [name=Energizer, price=12.0, propMap={numInPackage=8, make=US}]
Product [name=Apple Drive, price=200.0, propMap={expandable=false, type=External}]
This setup made the architecture scalable, maintainable and modifiable. The map keys always reported what was in there in case in doubt. Adding is easy and so is modifying.
Does having a class for each product make sense?
In real life situation, it rarely makes sense. They are just making up some example to make you get the feeling of it.
Just imagine your online shop sells CD players, now you want to add some MD players in your product list, and you need to change your code and redeploy the application just because of it. Non-sense huh?
Unless you have bunch of specific function for some specific type of product, having a dedicated class for such type of product will make sense. (e.g. Product, PhysicallyDeliverableProduct something like that. Still there are better way to design it though)
In real life, the way to solve the issue in your question, is mostly by designing your Product to keep some arbitrary properties (e.g. keeping a Map<String,Object>, so you can put ["rechargeable", true] for a battery you add on your site.
Design pattern? I think what you are looking for is still far from required to make use of patterns. Personally I will suggest you to take a look on the book "Analysis Pattern" by Martin Fowler. You may not be able to use the design in it directly, but it give you feel on what real life design looks like
Does having a class for each product make sense?
To me it absolutely makes sense to have separate classes for separate products.
That makes your code more loosely coupled. In future if you want to change the implementation of a particular product, changing the code won't mess up the implementation of other products if you have a separate class for that. The generic methods & properties you can put in an abstract class.
a pattern for achieving this?
You might want to look at the Factory & template pattern.
You can create an interface Product & all the classes will implement that interface & define their own implementations.
Use abstract class only when you want to provide a default behaviour to your methods. For an instance have a look at the template pattern here.
An abstract class game is created which defines the play method. initialize & startPlay etc can have their respective definition in the subclasses but the play method will always run the other methods.
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//template method
public final void play(){
//initialize the game
initialize();
//start game
startPlay();
//end game
endPlay();
}
}
If you don't intend to provide any default behaviour rather just declare the properties & methods in an interface Product & let the classes implement that.
interface Product{
String NAME="defaultName";
Integer PRICE=5;
initialCost(); // example of a generic method
}
//Note that name & price if you declare those in interface will be treated as constants.
class Battery implements Product{
Boolean rechargable =false;
public void initialCost(){
//method definition
}
}
class CdDrive implements Product{
Integer capacity = xxxx;
public void initialCost(){
//CdDrive method definition
}
}
You can create the objects as
Product product = new Battery();
Product nextProduct = new CdDrive();
this makes your code loosely coupled. Also known as programming to an interface.
I have to serialize a project and it's the first time I use serialization. After getting informed about it, I thought of two possible problems: my classes have atributes which type is another different class that has atributes which type is the first class (explained poorly, but can see in the code) and the fact that I use ArrayLists (which I've read can't be serialized). So I decided to try with a very simplified version of the project:
A group, this containts an ArrayList of Person:
public class Group implements Serializable {
private static final long serialVersionUID = 1L;
private Person leader;
private List<Person> members;
private int number;
public Group(Person leader, int number) {
this.leader = leader;
this.number = number;
this.members = new ArrayList<Person>();
this.members.add(leader);
}
public void addMember(Person p) {
this.members.add(p);
}
public int getNumber() {
return number;
}
}
A person, this contains an ArrayList of Groups:
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private List<Group> groups;
private String name;
public Person(String name) {
this.name = name;
this.groups = new ArrayList<Group>();
}
public Group createGroup(int number) {
Group g = new Group(this, number);
this.groups.add(g);
return g;
}
public void joinGroup(Group g) {
this.groups.add(g);
g.addMember(this);
}
}
And a main method which creates a few groups and people and uses writeObject() to write them into a file, plus another main that uses readObject() to get the objects back (it only uses readObject() and prints them).
I didn't expect this to work for the reasons mentioned above, but it worked perfectly, so I tried to serialize my main project (way more complex) but it didn't work (huge stack trace, simply saying "User", which is the equivalent to person, is not serializable).
Is there any reason for this or any major flaw that I should take into account?
I apologize for not including the two main methods I use, as well as none of the stacktrace or the main project, but I didn't want to make this question extremely long.
my classes have atributes which type is another different class that has atributes which type is the first class (explained poorly, but can see in the code)
Incomprehensible. Both Java and Serialization handle circular dependencies, if that's what you're talking about.
and the fact that I use ArrayLists (which I've read can't be serialized)
Wrong.
simply saying "User", which is the equivalent to person, is not serializable
So User doesn't implement Serializable.
Is there any reason for this or any major flaw that I should take into account?
Make User implement Serializable.Same for any other class that gives you the same message.
You need to read the Object Serialization Specification and the relevant Javadoc, and stop relying on arbitrary Internet rubbish.
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.