Reputation: 7139
Imagine situation:
I have got two classes
public class Fruit{
}
and:
public class FruitOnSale extends Fruit{
int price;
public int getPrice() or something
}
My program has one fruit and one fruitOnSale object. I would like to create completly new (clone) fruit2 [Fruit] based on the fruitOnSale (for example somebody has bought fruitOnSale and it needs to appear in his bag but as a normal fruit cause it is no more in shop). The method getPrice and field price are deleted during it. Then backwards - somebody creates a shop (...) and puts his fruit on sale. Now I need to convert fruit to FruitOnSale (I want it to be in the shop as 'on sale' and in my bag as 'normal', but as independent objects).
These classes will be rebuilded, modified and lots work may be done on them, so I don't want to manualy rewrite them just by copying every field because it's sensless. Is it possible through clonning? Or have you got better ideas?
Upvotes: 0
Views: 70
Reputation: 95538
Use composition:
public class Fruit {
// your regular fruit class
}
Your "fruit on sale":
public class FruitOnSale {
private Fruit fruit;
private int price;
public FruitOnSale(Fruit fruit, int price) {
this.fruit = new Fruit(fruit.getName());
this.price = price;
}
public Fruit getFruit() {
return Fruit(fruit.getName());
}
}
Now you can construct FruitOnSale
instances by passing in a Fruit
instance, and you can get a Fruit
instance from FruitOnSale
instance as well. Notice that when you initialize a FruitOnSale
instance with a Fruit
instance, it creates a "copy" of the Fruit
instance. It's good to do this, otherwise you could modify the original Fruit
instance, which would then affect the FruitOnSale
instance. This is not what you want, if you are assuming that these are immutable. Similarly, getFruit()
doesn't return a reference to the internal instance, but creates an entirely-new Fruit
instance as well.
While solving this particular example using inheritance does not violate the Liskov Substitution Principle, in general it is a good idea to think about the impact of extending the base class. For example, there might be some things that you can do with Fruit
, that don't make sense with FruitOnSale
(i.e., could lead to inconsistent, illogical, or unpredictable behavior); this would be an example of LSP being violated.
Upvotes: 3
Reputation: 8405
Cloning and Inheritance are two very different and very unrelated concepts in which both is unlikely to help you in your current case, if I understand you correctly.
Cloning normally refers to when you want to duplicate existing objects at runtime, thus the term should be avoided when used in a programming context unless the subject matter actually has relevance to the concept of object cloning.
Inheritance is used in contexts where you want to provide a more specific version or an alternative implementation of something, thereby extending the features of the more vague/abstract version with addition/altered functionality.
To give an example, we can declare two classes as follows:
public class WoodenFurniture{
public void burn(){
// Implementation here
}
}
and
public class WoodenChair extends WoodenFurniture{
public void sit(){
// Implementation here
}
}
Note in this case, WoodenChair
is a more specific version of WoodenFurniture
and thus WoodenChair
inherits all functionality of WoodenFurniture
, including the aforementioned burn()
method.
Whilst your Fruit
and FruitOnSale
class demonstrates such a relationship, where FruitOnSale
is a more specific version of Fruit
, your application of inheritance is incorrect.
In your question body, you suggest mutating a Fruit
object between multiple states carrying different information should be done through inheritance, which is only true if you are continuously adding or specifying detail to your current object. In this particular case, composition should be used, as described by Vivin Paliath.
But in the case you are describing, you want to repeatedly change or toggle between different states of the same object. Especially by saying method getPrice and field price are deleted during it
you demonstrate inheritance is not what you want. This should be done by adding fields to your original object to append state-specific information as opposed to the creation of multiple classes, as follows:
public class Fruit{
private boolean onSale = false;
private int price = 0;
/**
* Retrieves the price of the fruit if it is on sale.
*/
public int getPrice(){
// Check if the fruit is in the onSale state
if(!onSale){
// Rather than throwing exception, you can alternatively return an invalid price e.g. -1 to denote "not for sale"
throw new IllegalStateException("not on sale");
}
return price;
}
public void putOnSale(int price){
this.price = price;
onSale = true;
}
public void takeOffSale(){
onSale = false;
}
}
The class above represents an example implementation of something on the lines of what you want. In this case, we do not need to go through the trouble of converting between object types nor break any inheritance policy regarding how objects should interact.
Upvotes: 0