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);
Related
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).
I am learning software design now. I am a front-end guy so this may be a stupid question, but I really want to know the answer. Hope you could help me.
I have to design an E-commerce system. More specifically, I am designing the buying system in E-commerce. I have done some research on how to do it and found EAV. But after knowing the EAV is the anti-pattern, I don't want to use it and also I have to keep it simple for a beginner like me to understand the design.
Here is the class diagram I have designed by myself.
And of course, I don't think this design is correct. I have spent like three days doing research and thinking about how to solve the Product and ProductType problem.
I just want to have a product like an iPhone, for example, has the attributes belong to the phone, a coke has the attributes belong to the drink, etc.
How could I do this?
Please tell me how to solve this problem in a simple way, cause I am new to this. Some articles or books about software design could be appreciated too.
Thank you <3
Basically you know that all the products have (at least) a product type. And you know that a product type instance will end up being a drink, a telephone, etc. So, you first need
Product Type Abstractization
You will need to make sure that ProductType is either an interface or an abstract class or a base class. An interface is a declared entity type, whose capabilities are known, but not implemented. It is the job of the classes implementing the interface to implement its methods. An abstract class is a fully declared, but only partially defined entity type. If you have an abstract class, then you are able to implement some of its methods, but you delegate the implementation of some of its method to its implementing subclasses. A base class is a class which is fully defined.
So your first decision is to make ProductType one of the following:
interface
abstract class
base class
You will need to think about what the common capabilities of product types are. If they should have some methods which work exactly the same, then you do not necessarily need an interface, but you will need an abstract class or a base class. If you decide not to define an interface at this point, that's fine. Later you can define it if you realize that you need it anyway. So, assuming that the methods of the separate product types are at least partially common, you will need to have some class. By default it should be a base class, that is, a normal class which has all the methods a ProductType should have implemented. Son't worry, if some specific product types should behave in a different manner in the case of some methods in comparison to the base class, you can always override base class methods for subclasses.
However, you might need an abstract class. In order to decide whether an abstract class is the way to go is to find out whether there is at least such a method that should NOT be implemented by the base class in any circumstances, because that method is always known only on subclass-level. For example, if you have an evaluate method, then you will probably need to implement it separately for your product types, because a phone is evaluated in a different manner in comparison to car.
Next, you need to define specific ProductType subclasses, that is, classes which extends/implement ProductType. We know that a ProductType may have 0 or more Products, but can a product be of more product types?
Handling one-to-many vs. many-to-many relations
A product will need to have a ProductType if there is no possibility for more product types to be associated to a single Product. Otherwise you will need a collection of product types by product.
Abstractization of Product
Since Product is also something much more general, you will probably need to invoke Product methods from ProductType. This means that you will need to decide whether Product is an:
interface
abstract class
base class
as well, with a similar thought process as the one you have used when decided what ProductType should be.
ProductType and Product trees
It's a big question whether there can be subtypes, sub-subtypes, etc. for ProductType and Product. If that's the case, you will need to implement trees for them with proper insert/update/delete/search functionalities, as you need them
Use your abstractizations
Whenever possible, do not refer to specific product types, because then you will have to copy-paste that code for other products and product types. Whenever the same pattern is true for all your product types or products, refer them by their most abstract representation (their interface, abstract class or base class, respectively) and only use concrete types at instantiation and when you are forced to.
Factories
Use factory methods for instantiation instead of constructors, because a factory method can return the instance of a subtype if that's what you need.
So, I have an object-oriented assignment to do. Small part of it is to make a graph, made out of nodes, which can be either a type category or type product.
The category has only a name ([a-zA-Z0-9]+) as parameters.
The product hast a name ([a-zA-Z0-9]+) and an id (>=0).
At the beginning a made just a node, with two objects category in product, which where both null, and depending on the input I created an instance of one of the two things, and everything was fine.
I really put a thought in it and after I checked the lectures I found about the thing abstract classes :D . No my idea is to make Node abstract and Product and Category extending Node,since:
Category has setter and getter for Name and toString
Product has setter and getter for Name AND ID (of course) and toString.
Setter,getter and toString for Name are identical.
There's a differnce in the constructor for Product, because it sets also the ID.
So,
Is it going to work that way, is it better?
Can I create a Node and then after the input say -> this node is from type category
You cannot just create a Node if it is abstract.
You should be getting the input, and in that probably the type that wants to be created, and create the appropriate non abstract class for that one.
Alternatively you can create them as Category and if the user types an Id create a new Product and copy the data across from the first object to the second. But that doesn't makes much sense.
Seems like category should just be part of product. That is you have a category class, and a product class which has two properties: category class and id. That way, you can create a category out of any point on your graph, and then if it is a product, pass it to a second constructor to give it an id.
I think this should be an abstract method validate that each node type can implement independently.
Node suggests that this is a graph of states that you're navigating. Perhaps you want a method to fire on entering or leaving that state. Each type can put whatever they need into it. Interfaces and strategy patterns will help here.
Keep the graph separate from what's done.
In a game, the server might have to send the client a packet with info to, lets say, add an Enemy. The data to add such an enemy might be similar to every enemy (position, id...) but there is a need to distinguish which enemy it is. Is it the zombie? A werewolf? Well.
I can remember two ways of doing this:
1 - Create an Enum. So I could have an Enum with every type of enemy there is, and in my Packet, I would send that type.
Pros: Only one Packet to add several types of enemies, only one method to handle the receiving of it.
Cons: Everytime I want to add a new enemy, i must create a new entry on the enum, and the method which receives will most likely be an annoying big switch-case.
2 - Create a packet per enemy, each with a different "handle" method
Pros: It "seems" more organized since each element has an assigned packet and method, and no need to add an entry to the enum (although id need to add a new handle method so.... yeah.)
Cons: Many enemies mean many packets, which mean many handle methods, which might be a mess.
So, basicly, tl:dr, either i have a "PacketAddEnemy" with an enum like EnemyType and a few switch-cases, or I have "PacketAddZombie", "PacketAddWerewolf", etc, but end up with a spam of packets and methods.
I prefer the first option, but I dislike both. I wonder if there's interesting alternatives?
There are many different ways to handle this. My favorite way to handle this is similar to option one that you posted. Where each Entity has a unique type ID. Instead of one long switch statement to say create entities, you could instead use a more reflection based approach. It's a slightly slower way but it does provide for a very nice and clean interface.
Just remember that there are a lot of ways to handle this, and this is just my preferred way. Each game handles this differently and you really just have to go with something you like.
Example:
public enum EntityIDs {
Zombie( EntityZombie.class ),
Werewolf( EntityWerewolf.class );
// And so on for all of your entities
public Class< ? extends Entity > entityClass;
private EntityIDs( Class< ? extends Entity > cl ) {
this.entityClass = cl;
}
public static Entity createEntity( int id ) {
Class< ? extends Entity > cl = EntityIDs.values()[ id ].entityClass;
return cl.newInstance();
}
}
You would then receive a type ID from the server and common data, such as location. That ID could be the ordinal of the Entity Type, or some other way you decide to map it to their type. You can then use the entityClass field to reflectively create your entities. Of course this requires that you still list out every entity in an enum, but creating a new one is as simple as a single line. This does require that all Entities subclass a common super class, such as Entity in this case. It also requires that each Entity subclass have a common constructor, usually just a default constructor with initialization done after construction.
Having a common super class does simplify part of your problem. You would put all common data, such as location, inside the super class. When you want to move an entity you would not need to care what type of entity it is, you would only need to know which entity and where it was moving.
World world = ...;
Entity entity = world.getEntity( entityId );
if( entity != null ) {
entity.move( newX, newY );
}
Again I would like to reiterate this is only one way to do it and is in no way the only way to do this. This can easily be expanded to many different solutions that really depend on your preferences. It is in no way a complete example, but just a general idea of my preferred solution.
This does come with performance costs because reflection is not very fast. It usually consists of several more method invocations for each invocation. You could change this to use a factory pattern instead where each Entity type has an EntityCreator that is responsible for creating each Entity.
For context, we are storing most of our data as JSON strings. This works very well with Hadoop on the backend and is easy to handle in Ruby on the front end. My data types fit the natural pattern for inheritance.
For simplicity, lets say I have a class Pet and a process FeedPet that feeds a pet. I also have a process WalkDog that only applies to Dog, which is a kind of pet. My data is organized such that I never need to worry about trying to walk a pet that isn't a dog.
What I would like to do is have Pet and Dog extends Pet, with Dog having an additional method "getLeash()", but I can't figure out how to map this to JSON.
Instead, I have a class Pet with a species data hashmap, so the WalkDog process would call pet.getSpeciesData("leash") instead of dog.getLeash().
I can create a Dog extends Pet, and I can serialize that to JSON using the Jackson library. The JSON object will have a leash field. But assume that I want to feed all the pets. All pets have a getFood() method. So the FeedPet process deserializes the objects to Pet. But this loses the leash field.
The WalkDog process can do this because it knows all of its input is going to be Dogs, so it can read it as a Dog and write it back out as a Dog.
Is there any way to serialize java objects to JSON such that I can preserve their type? I'm thinking something like Rails single table inheritance, but it would have to be something that the JSON libraries understand.
To make it work you must both embed some object type information in data (where it is only useful for deserializing) and usually use external schema definition which otherwise would not be needed (like XML Schema for xml; since that's basically a generic type system).
This has same problems as ORM has: Hibernate has to use ugly work-arounds (n+1 - way joins, "super tables" or discriminator fields).
Or another way to put it: data mapping/binding is not quite the same as object serialization/deserialization (latter tries to preserve more of object identity).
Here I am assuming that what you want is basically something like:
Pet pet = mapper.readValue(jsonString, Pet.class);
// (and possibly get an exception if Pet is an abstract class...)
Leash l = ((Dog) pet).getLeash();
If this is not the case, you could just simply bind to Dog
Dog dog = mapper.readValue(jsonString, Dog.class);
So anyway: Jackson project has feature request for doing just this, which allow you to do what (I think) you want.
However, this solution will mostly work for Java, as there is no standard way of passing Object type info within JSON. With XML this can sort of be done with XML Schema defined "xsi:type" attribute; which identifies Schema type, which is then mapped to class (yes, rather complicated way, but it does work).
UPDATE: Jackson 1.5 added support for this (i.e. implemented JACKSON-91 feature request), so it can be used for generating type identifiers, to allow proper handling of polymorphic types. It should work with non-Java systems too, given that you can fully configure details of how type information is to be included; and is NOT limited to using Java class names.
I've not had that much experience using JSON other than for fixtures in django, but in that instance I just have a "model" key, with the associated value.
It is then up to the program that is interpreting the objects to determine their type and inheritance hierarchy.
What I'm trying to say is that it is irrelevant what methods are available, as this doesn't need to be serialised. Only the object's name and attributes.
-- update
After reading your question again, it seems like your process is deserialising into the parent class, rather than the actual class. Since your dog class inherits from pet, you just want to make sure your deserialiser is creating objects of the most specialised class.
I don't know about the Jackson library, but if you can set it to have a type of model field, then that might be the go.