I have an abstract super class with 40 attributes. I also have 2 subclasses that basically extend the super class. Now I want to convert one child class with another.
public abstract class ParentClass{
// ... many attributes
}
public ChildClassA extends ParentClass{}
public ChildClassB extends ParentClass{}
A simple class cast like this is not working and throws ClassCastException:
public ChildClassA to(){
return (ChildClassA) ((ParentClass) this);
}
I could manually write a copy constructor but its tedious work.
Another approach is to serialize and convert. For example using XML or JSON. But that is used for cloning a class and again deserializing would throw class cast exception.
Is there are any other better ways?
EDIT:
Since people have asked for design decision:
I have 2 tables of identical columns. One table has data and the other one doesn't. I have to retrieve rows from original table -> do processing -> put back in second table.
So to minimize code complexity I have super class entity (JPA) which has all the fields (more than 40 fields, annotated with`) and have 2 subclasses extending from it (because I can only have 1 #Table annotation per class).
Now to do processing I need to retrieve data from original table to original sub class. Create a new second subclass and copy values from original to new. Do processing. Persist 2nd entity onto 2nd table.
I would question the design decision of extending the base class with subclasses that don't add anything, especially since they have to be converted from one to another. You could use one class instead, but add an enum field that differentiates the types from one another. Then the conversion would be simply changing this field to a different value.
However, if you really need them to be different classes and be able to convert from one to another, and you don't want to write tedious code to copy fields manually, you could look up some Java mapping frameworks, like MapStruct.
A simple class cast like this is not working and throws ClassCastException
Sure, that an expected behavior. It's not possible to type cast between two classes like ChildClassA and ChildClassB that are not bound with IS-A relationship, they are siblings, they don't extend each other, and therefore they are not compatible.
I have an abstract super class with 40 attributes.
If the number of properties is unmanageable, that's clearly a code smell. I suspect that some of these 40 properties can be "folded" into several objects, which will make sense in your domain model.
I could manually write a copy constructor but its tedious work.
Since you have 40 properties, I guess primarily concern is to bring the code to the state when you can more easily maintain it rather than amount of typing. And I've given you advice on that point.
And as a tool for conversion, I would rather declare a method like toChildClassB() because it would be more expressive than a constructor call new ChildClassB(childA).
Related
I have the main abstract class that is a base for bunch of classes. Some of them does not need all the fields and methods from the main abstract class, so I have created second abstract class and splitted main abstract class into two parts. The main abstract class contains, for example, a, x fields and their getters/setters, the second abstract class inherits from the main and contains additional b, c fields and their getter/setters. There are simple classes that are inheriting from the main class,and more complicated are inheriting from the second class. I want to create objects of each class as instances of the main class. Is it right way to do that? I have to type check and cast when I want to use methods from the second abstract class. It makes my code complicated. How can I solve this problem?
MainAbstractClass ---> SecondAbstractClass ---> MyComplicatedClasses
|
|
V
MySimpleClasses
One of the OO principles is Favor composition over inheritance.
This means that common behavior is not provided through base classes but via Component classes which are passed in via dependency injection (preferably as constructor parameters.
The answer depends on your actual needs.
You can instead choose to store the extended abstract class specific fields in a class that does not implement your base class and make it a member of more complicated classes.
You can choose to keep everything in a single base class and nothing forces you to use all the fields of an interface in every class that implemented your interface.
You can also keep using your approach but since you store the classes as an instance of the base class, it will be hard to read.
I believe that if you think code does not look very good, it is probably not good. However, there is usually no single answer to this kind of design questions and the best solution is relative to your preferences.
I think this need of type cast is a smell of fragile design. Here when we assume MyComplicatedClass ISA KIND OF MainAbstractClass as shown by TJ Crowder then object must behave as MainAbstractClass (meaning it can honor only API of MainAbstractClass). If it expects special treatment as MyComplicatedClass its false commitment and will need Casting. Such casting (by identifying type) goes against OO principles and kills polymorphism. Later this will end up in Ladder of InstanceOf and type casts as in the scenarios rightly pointed out by T.J. Crowder.
I would suggest readdress the design. e.g. though our all user defined type instances ARE KIND OF Object, but we use Object API only for methods defined in Object class. We do not use Object o = new MyClass(). There are occasions in frameworks or like Object.equals() method where type cast is needed as API is defined before even concrete extension is written. But it is not a good idea for such simple complete (without open hooks for extensions) Hierarchies.
Is there a way where I can prevent the parent class to be serialized?
When we do a serialization of the subclass all the way up till the parent class the serialization is performed.
Can I restrict the serialization of the parent classes and serialize the only sub class I am working on?
It is possible. Just declare your class as implements Externalizable and write exactly what you need in the writeExternal() method, taking care not to serialize anything from the superclass, and read exactly that back in the readExternal() method.
Or, just implement Serializable and provide your own readObject()/writeObject() methods, again taking care not to serialize anything from the superclass, and in this case also not calling defaultWriteObject() or defaultReadObject().
In both cases the actual serialization of the current class's data is entirely up to you.
Whilst it is technically possible to fine tune each level of inheritance on its own - even to the extent of excluding super class fields - you might want to step back here.
Basically there are two cases:
The super class does not have any fields / state. Then you have nothing to exclude anyway.
The super class has state, represented by fields of that class.
So how do you think to meaningfully address the second part? You see when you allow deserialisation without the data for the super class fields - that means that you might have to do a lot of additional testing. To make sure that super class methods don't throw exceptions - because all of a sudden fields are null instead of being initialized.
In other words: it is possible that "leaving out" all these values - you are creating objects which behave completely different. Are you prepared for handling all the effects of that?
Meanung: skipping super class fields requires you to interfere with serialization code. It might require a lot of additional testing effort. And what do you gain? A few bytes less of data transfer at runtime.
Beyond that: what is the purpose of an inheretance hierarchy that has 4 levels - but where the super class state is irrelevant?
So my non-answer: carefully consider if your idea is really the best OO design to solve the underlying requirements.
We have 3 types of attributes in our project: CategoryAttribute, ProductAttribute and ProductTypeAttribute. These are outside of our control as they come from autogenerated classes and may contain attribute values of different types e.g. text, number or image. Now, each attribute has its own strategy to retrieve attributeValue. For simplicity, let's assume that all 3 of them have TextStrategy, NumberStrategy and ImageStrategy.
Example strategy:
#Component
public class CategoryImageAttributeStrategy implements CategoryAttributeStrategy {
#Override
public boolean isApplicable(CategoryAttribute attribute) {
return attribute.getImage() != null;
}
#Override
public Object getAttributeValue(CategoryAttribute attribute) {
//return attribute value here
//may be different or may be the same
//for ProductImageAttributeStrategy and ProductTypeImageAttributeStrategy
}
}
While getting image value may be different for all of them, getting text value is the same and we end up with 3 classes of almost the same code and I really really really don't like duplicating code.
I thought about creating an abstract class/default interface for each strategy type e.g. DefaultTextStrategy that all 3 text strategies would inherit from and either use default code provided higher or override it with own implementation, however I'm not really satisfied with this approach as it requires to create even more classes for such a simple task.
Maybe is it even possible to combine strategies of the same type (e.g. image) into one?
I would really like to hear what more experienced folks have to say in this matter as I would like to learn and improve.
Thanks in advance for your time.
There should be only 3 strategies. TextStrategy, NumberStrategy and ImageStrategy which extend the base strategy. Mixing attributes and strategy will make it confusing as both are actually independent and have many to many relationship with one another.
Let the 3 attributes extend a single Attribute class : CategoryAttribute, ProductAttribute and ProductTypeAttribute.
Let the strategies decide on what needs to be done based on the Attribute class object being passed to it. For Text strategy there would be single implementation. For Image strategy, you may require special handling for the one class.
Here's what I did:
First, I created an interface for all types of strategies named "AttributeValueStrategy". Then added 3 callbacks (type specific, e.g. NumberValueCallback etc.). Now, each strategy implements callback interface of its type and AttributeValueStrategy interface. Then there's DefaultStrategyMethods class that contains default "getAtrribute" for each type and the actual strategy call the defaultStrategyMethods (like below) or just implements its own code.
#Override
public Object getAttributeValue(Object attribute) {
return defaultStrategyMethods.getNumberValue(attribute, this);
}
Callbacks are created because only the actual strategy knows which class should it cast to (and has a method to do that), and DefaultStrategyMethods needs to use it so that's why I pass "this" as second argument (which is the callback itself).
No more duplicates, everything is clear and clean.
I am making a modification and a separate application that allows replays to be saved for a certain game.
What I have to serialize and deserialize is an 2 arrays of class ContO, arrays of class Plane, Trackers, and a class Medium, and that is no problem.
To extend this functionality, I decide to reconstruct it in the separate application so that it supports 2 versions of said game. The way I plan to do this is to use abstract classes named Medium, ContO, Plane, and Trackers, and the classes that will extend those will be named things like MediumVersion1 and MediumVersion2, ContOVersion1, and so on.
In the original game files the class is named ContO, Plane, Trackers, and Medium for both versions, and what I wonder is: by changing the name of the class to reflect the version of the file that will be deserialized, will it effect the deserialization process?
For example, I serialize the class as the name of ContO in the original game files, but deserialize it under a new class name named ContOVersion1, but contains the exact same variables.
I just tried this and the answer is you cannot change the class name. You will end up with a ClassCastException when you try to cast the object you get back from ObjectInputStream.readObject() into your new class with a different name. This is the case even if you keep the same serialVersionUID on both classes.
You can definitely not do this.
The original class and package names are encoded along with the data, and the incoming object is constructed as that class, so, to avoid a class cast exception, what you cast it to must be identical, as must many other aspects of the class - but not all of them. See the Object Versioning chapter of the Object Serialization Specification for more information.
All,
I have to be doing this wrong. It seemed like a good idea at the time but as I get deeper into it, I think there is a more proper programmatic way of going about it. Thus I ask you...
One note. I'm using Google AppEngine and the Datastore to store this information.
Ok... lets say I have a Super Class of Vehicle, which then has 3 Sub-Classes... Car, Truck, Motorcycle.
In the Super Class, there are 3 properties... Manufacturer, Model, Type
For example, these might be:
Manufacturer: Ford
Model: Focus
Type: Car
So in the Datastore, I have numerous Vehicle entities with these properties.
So if the user wants to see all the cars... I pull everyhing with a "Car" type.
If the user then wants to add one of these Vehicles to a "favorites" list, I then convert the Vehicle object into its specific Sub-Class based upon what type it is. This then adds the extra properties of that specific Sub-Class.
This new child entity is store in the Datastore with its added properties.
So basically, I'm downcasting, for example, from a Vehicle to a Car. I have done this by creating an extra constuctor in the Car class that takes Vehicle as an argument. Once created, the Car object now has all the properties (Manufacturer, Model, Type) set, and all the new properties that come with its specific implementation.
This just seems convoluted and wrong. It works but there has got to be a better way of doing this.
The main reason I chose this way is because of the way the GAE Datastore works. Its "cheaper" to store the Super Class and its limited properties and query those. Long story.
I'm trying to wrap my head around using Interfaces and/or Abstract classes for this but I wanted to get all of your input.
Thanks for the help.
I don't think you want a super/sub class structure here. Your problem as described has you "changing" an object from one type to another, and you cannot change the type of a Java object. You can create a new object, but then you have to move all your information from one to another, and maintenance becomes a problem.
I suggest that you have a class that represents your vehicle, and that it contain a reference to type-specific information; the classes representing each specific type can all extend something, and probably should so that methods within vehicle trying to do something with the type can call a common method to do it regardless of type. But this way, once you decide the specific type, you can add it to an existing vehicle object instead of "changing" it.
You could also explore whether an enumerated type would serve your purpose for type-specific data -- enum types can take constructors, have additional methods, etc. - the Oracle/Java tutorial on enums covers that pretty well.
The type of vehicle is encoded twice: once as an object type, and once as a property. Get rid of one of these, so that there is not a possibility of having a Truck (object type) with property value set to Car. Keep your object structure, or property pointing out the kind of vehicle (I recommend using an Enum), but not both.
To downcast, you do not need to create a new object of the child type. Just downcast:
Car myCar = (vehicle instanceof Car ? (Car)vehicle : null);