I'm currently working on an "item drop" system, where items (and their properties) are randomly generated upon slaying an enemy. The current system I have is a hierarchy of classes, with Item being the root super class. Each class has specific properties common to all subclasses.
Ideally upon dropping an item, program will randomly select one property of the item and move down the hierarchy tree accordingly. For example, the process is as follows:
Class | Randomly Selected Property determining path in tree:
Item | ItemType -> Equipable | EquipType -> Weapon | WeaponType -> etc.
Example code:
abstract class Item
{
private Type itemType;
private String itemName;
private int itemLevel;
private Rarity itemRarity;
private boolean questItem;
private int itemPrice;
public Item(String name)
{
itemType = Type.randomize();
itemName = name;
itemLevel = randomizeLevel(pLvl, eLvl);
itemRarity = Rarity.randomize(bonus, pLvl, eLvl, iLvl);
questItem = false;
itemPrice = determinePrice();
}
}
Type is an enum deciding the next level in the hierarchy. With this system, I dont know how to let the program determine the next level, and then proceed to it.
The problem I've run into is that I've realized in order for this to work, I have to work from the bottom of the hierarchy, up. Is there a way for me to work from the top-down, meaning I can start with a basic Item class and procedurally work my way down (using the methods I created to randomly select the properties).
If not, is there a specific way I should implement this system?
You can get a list of all your enums from the enum class - the order is the order in which they are declared so if you declare them in hierarchy order, you can traverse the list however you want. The relevant oracle doc is here:
https://docs.oracle.com/javase/tutorial/reflect/special/enumMembers.html
If you want to work your way from the top down, especially if the subclass selection depends on the choices made when constructing the superclass, then it's probably much better to favor composition over inheritance. So, if for Item you have Type specific information, you could make Type contain all the properties you could possibly want, including references to subsequent objects down this (conceptual) hierarchy.
At any point, of course, you can in addition make a small class hierarchy out of Item, Type, and so on as long as you know before creating the object the specific subclass it should be. Otherwise, composition would be the only way to create your item in the fashion you describe.
You could have a static method in each class that determines the 'next transition'(thinking of the package of 'items' as a tree.
So
// untested code
String nextClass = "Item";
// define a helper method
Class x = getClass(nextClass);
while( x.hasMore() == true )
{
nextClass = x.getNextClass();
x = getClass(nextClass);
}
// reflection here on Class 'x' (whatever that is...)
Then you can use reflection to instantiate the last class.
This probably is a bad idea. But it would 'walk' a tree of well formed classes
If I understand your goal, and try to reformulate:
you have a top type: Item
you have (or create now, or further perhaps ?) subclasses of Item, by adding some property: Equipable, then Weapon, etc.
from top (Item), you want to random select a subclass (Equipable ? yes/no ? if yes => equip Type, etc.
What I suggest:
dont break notion of subclass: a parent doesnt need to know by advance his children
then take a class (1st: item, and so on), search subclasses by reflection
select between children: at this point you must define how you categorize between children: any new variable, or any variable begining by a prefix. For example, you can define final static int category_weapon=1; (or true, false, ...)
then to iterate, you go from top, get children, get these static variables and value, and choose at random between these children, and do it again
Another way to caracterize: use Interfaces (weapon, equipable, ...): the benefit is you can then apply predefined method (for weapon, ...)
Cheaper : dont use any variable, just use the name of the children class to choose the next.
A good way to choose: define precisely what you'll do with these objects.
Hope it helps.
Related
Noob Java question here. I am wondering if there is a standard way to add additional/external properties to a POJO. i.e., say I have a User Object that I add to an ArrayList in my program. This Object will contain things like first name, last name, address, email, phone, etc., corresponding to whatever is defined in my database.
Now say that I have the requirement to include external attributes along with said User, such as Employer ID, Vehicle Plate #, Smartphone type. I will need to be able to include these extra properties when adding a User to my ArrayList - Is it possible to attach these strictly with Java so that I can have acces to them?
I've thought of going with something like a Value Object, in where the VO would include all the User Properties along with the extra fields to be added from outside Classes, but want to explore more possibilities. Any ideas? Thanks much
You have many possibilities. Here are a few that immediately spring to mind:
Refactor the User class. This is the obvious one, so I presume you have a good reason for not doing so.
Write a class that extends User, containing this information. Presuming you're only storing this information for a subset of the users that this information applies to, this makes the most sense.
Use composition - create a new class that holds a user instance and then any other information you want to add to it.
One big influence on what design you use will be whether all additional values are unique, or if a User can have multiple smartphones, vehicles, etc.
If all additional fields are all unique you can just slide in java.util.Properties (or other Maps). Your User class needs at least
import java.util.Properties;
class User
{
Properties extra_attr = new Properties();
// ... existing code ...
public void setExtraAttr(String field, String value) {
extra_attr.setProperty(field,value);
}
public String getExtraAttr(String field) {
return extra_attr.getProperty(field);
}
}
Then use calls like some_user.setExtraAttr("Employer ID","314159"); and some_user.getExtraAttr("Employer ID"); to set and get your extra attributes.
If you need multiplicity you may need a different approach, or you can just code over your implementation of Properties. For instance, you can rewrite setExtraAttr() to look for existing keys and add an index
public void setExtraAttr(String field, String value) {
if(extra_attr.getProperty(field) == null)
extra_attr.setProperty(field,value);
else {
int index = 1;
while(extra_attr.getProperty(field+index) != null)
index++;
extra_attr.setProperty(field+index,value);
}
}
You then need some kind of loop where ever you get attributes to look for and handle the multiple extra records.
I'm currently taking a course in Software Engineering (I have to).
We have a whole bunch of tasks which require us to use design patterns in Java. Normally I'm just a PHP developer, so I don't have many skills in Java, which may be a problem.
The specific problem is: We have to use the composite pattern for following problem: Create a mathematic framework to solve terms. The term could be Number (double) or "/", "-" which connect two terms, or "sin" which uses one Term.
I have to create a UML Class Diagram to.
Which is this
I'm not sure if this is right. The two main questions I got about my class diagram are:
Is it correct to use value, and first/second for the Composites, because they only have either 1 or 2 Terms, or should I make a list with addmethod and make sure there are exactly 1/2 items in the list?
Should I create another Interface for the Composite Structures (Sin, Divide, Subtract)
Am I doing it right, or did I follow a bad/wrong approach?
Thank you
Bernd
The composite pattern really doesn't place any restrictions on how you represent the children of a composite node. In your case you could either have classes representing unary and binary operations or have separate classes for each operation.
The second option would look something like:
interface Term {
double getValue();
}
class Constant implements Term {
private double value;
public double getValue() {
return value;
}
}
class Divide implements Term {
private Term numerator;
private Term denominator;
public double getValue() {
return numerator.getValue() / denominator.getValue();
}
}
This is probably the closest representation of your UML. In this case there's no advantage in modelling the child terms as a List.
The other option I mentioned (which I would not recommend) is to have UnaryOperation and BinaryOperation classes and then define and enum for the operations. In this case the operation enumeration would contain the actual calculation logic. I think that's unnecessarily complex for your needs unless you have a large number of operations.
I'm sorry, but this isn't a correct implementation of the composite pattern. If you look at it, you'll see that you have no Composite (the object with add, remove, and getChild methods) class, and that you're aggregating the Leaf objects which you should not do.
If you're to apply the composite pattern to this problem, you need to come up with a class that contains the different operations to perform.
So, first create an abstract class called something like FrameworkItem. This corresponds to Component on the Composite pattern diagram. From this, derive another class called Term. This is your Composite, and is an aggregate of FrameworkItem. (Make sure it includes your add, remove, and getChild methods.) Finally, derive your Leaf classes individually (Number, Sin, Subtract, Divide etc.) from FrameworkItem as well, using simple association rather than aggregate.
Keep in mind that your Composite's solve() method needs to take a Leaf object as parameter, which tells it which one of its children's solve() methods it needs to call.
I've got loads of the following to implement.
validateParameter(field_name, field_type, field_validationMessage, visibleBoolean);
Instead of having 50-60 of these in a row, is there some form of nested hashmap/4d array I can use to build it up and loop through them?
Whats the best approach for doing something like that?
Thanks!
EDIT: Was 4 items.
What you could do is create a new Class that holds three values. (The type, the boolean, and name, or the fourth value (you didn't list it)). Then, when creating the HashMap, all you have to do is call the method to get your three values. It may seem like more work, but all you would have to do is create a simple loop to go through all of the values you need. Since I don't know exactly what it is that you're trying to do, all I can do is provide an example of what I'm trying to do. Hope it applies to your problem.
Anyways, creating the Class to hold the three(or four) values you need.
For example,
Class Fields{
String field_name;
Integer field_type;
Boolean validationMessageVisible;
Fields(String name, Integer type, Boolean mv) {
// this.field_name = name;
this.field_type = type;
this.validationMessageVisible = mv;
}
Then put them in a HashMap somewhat like this:
HashMap map = new HashMap<String, Triple>();
map.put(LOCAL STRING FOR NAME OF FIELD, new Field(new Integer(YOUR INTEGER),new Boolean(YOUR BOOLEAN)));
NOTE: This is only going to work as long as these three or four values can all be stored together. For example if you need all of the values to be stored separately for whatever reason it may be, then this won't work. Only if they can be grouped together without it affecting the function of the program, that this will work.
This was a quick brainstorm. Not sure if it will work, but think along these lines and I believe it should work out for you.
You may have to make a few edits, but this should get you in the right direction
P.S. Sorry for it being so wordy, just tried to get as many details out as possible.
The other answer is close but you don't need a key in this case.
Just define a class to contain your three fields. Create a List or array of that class. Loop over the list or array calling the method for each combination.
The approach I'd use is to create a POJO (or some POJOs) to store the values as attributes and validate attribute by attribute.
Since many times you're going to have the same validation per attribute type (e.g. dates and numbers can be validated by range, strings can be validated to ensure they´re not null or empty, etc), you could just iterate on these attributes using reflection (or even better, using annotations).
If you need to validate on the POJO level, you can still reuse these attribute-level validators via composition, while you add more specific validations are you´re going up in the abstraction level (going up means basic attributes -> pojos -> pojos that contain other pojos -> etc).
Passing several basic types as parameters of the same method is not good because the parameters themselves don't tell much and you can easily exchange two parameters of the same type by accident in the method call.
If do not have time please have a look at the example
I have two types of users, temporary users and permanent users.
Temporary users use the system as guest just provide their name and use it but system needs to track them.
Permanent users are those that are registered and permanent.
Once user create a permanent record for himself, I need to copy all the information that has been tracked while user was a guest to his permanent record.
Classes are as following,
#Entity
public class PermUser{
#Id
#GeneratedValue
private long id;
#OneToMany
private List Favorites favorites;
....
}
#Entity
public class Favorites {
#Id
#GeneratedValue
private long id;
#OneToMany (cascade = CascadeType.ALL)
#LazyCollection(LazyCollectionOption.FALSE)
private List <FavoriteItems> items;
...
}
#Entity
public class FavoriteItems {
#Id
#GeneratedValue
private long id;
private int quantity;
#ManyToOne
private Ball ball;
..
}
#Entity
public class TempUser extends PermUser{
private String date;
....
}
Problems is :
If I clone the tempUser object, I am copying the id parameters as well so when saving the perm user object it shows a message like "Duplicate entry '10' for key ...", I can not remove the tempUser first then save the permUser as if saving permUser failed I will miss the data. If I try to copy each ball of favoriteitems separately without id of item it would not be an efficient way.
Example (Question in one sentence: As shown blew a user may have more than one TempUser record and just one PermUser record, therefore I need to add information of all the TempUser records to that single PermUser record.)
Type of record | name | favorites | date
| | |
1)TempUser | Jack | 2 items | 1/1/2013
2)TempUser | Jack | 3 items | 1/4/2013
---------------------------------------------------------------------------
PermUser | Jack | 5 items ( 2 + 3 items from his temp records)
*Please note, I need to find a solution, and do not care if try a new solution rather than cloning the object.
The reason that I have two different classes is that tempUser has few additional attributes, I may also need to add favorites of few tempUsers to favorites list of one permUser. and also as mentioned above a user may have many different not related temp records
Forgive me if I'm missing something, but I don't think that TempUser and PermUser should be different classes. TempUser extends PermUser, which is an "is-a" relationship. Clearly, temporary users are not a type of permanent user. Your question doesn't give enough information to justify making them different -- perhaps they're the same class, and the difference can be expressed as a few new attributes? Eg:
#Entity
public class User{
#OneToMany(cascade = CascadeType.ALL)
private List Favorites favorites;
private boolean isTemporary;
....
}
The "transition" from temporary to permanent can be handled by some controller, making sure that isTemporary = false and that the other properties of a permanent user are appropriately set. This would completely side-step the cloning issue and would be much easier on your database.
I just had the same problem. I've been digging through many interesting articles and questions in boards like SO untill I had enough inspiration.
At first I also wanted to have sub classes for different types of users. It turns out that the idea itself is a design flaw:
Don't use inheritance for defining roles!
More Information here Subtle design: inheritance vs roles
Think of an user as a big container which just harbors other entities like credentials, preferences, contacts, items, userinformation, etc.
With this in mind you can easily change certain abilities/behaviour of certain users,
Of course you can define a role many users can play. Users playing the same role will have the same features.
If you have many entities/objects depending on each other you shoukd think of a building mechanism/pattern that sets up a certain user role in a well defined way.
Some thoughts: A proper way for JPA entities instantiation
If you had a builder/factory for users, your other problem wouldn't be that complex anymore.
Example (really basic, do not expect too much!)
public void changeUserRoleToPermanent (User currentUser) {
UserBuilder builder = new UserBuilder();
builder.setRole(Role.PERMANENT); // builder internally does all the plumping
// copy the stuff you want to keep
builder.setId(user.getId);
builder.setPrefences();
// ...
User newRoleUser = builder.build();
newRoleUser = entityManager.merge(newRoleUser);
entitymanager.detach(currentUser);
// delete old stuff
entityManager.remove(currentUser.getAccountInfo()); // Changed to different implementaion...
}
I admit, it is some work but you will have many possibilities once you have the infrastructure ready! You can then "invent" new stuff really fast!
I hope I could spread some ideas. I'm sorry for my miserable english.
As I agree with prior comments that if it is possible you should reevaluate these entities, but if that is not possible I suggest that you return a general User from the database and then caste that user as either PermUser or TempUser which both would be extensions of User, based on the presence of certain criteria.
For part 2 of your problem:
You are using CascadeType.ALL for the favorites relation. This includes CascadeType.REMOVE, which means a remove operation on the user will cascade to that entity. So specify an array of CascadeType values that doesn't include CascadeType.REMOVE.
See http://webarch.kuzeko.com/2011/11/hibernate-understanding-cascade-types/.
What I am going to suggest might not be that OO but hope will be effective. I am happy to keep PermUser and TempUser separate do not extend it, not binding them into is-a relationship also. So I will have two separate tables in database one for TempUser and one for PermUser thereby treating them as two seperate entities. Many will find it to be redundant.. but read on... we all know.. sometimes redundancy is good.. So now...
1) I don't know when a TempUser would want to become PermUser. So I will always have all TempUsers in separate table.
2) What would I do if a user always wants to be TempUser..? I still have separate TempUser table to refer to..
3) I am assuming that when a TempUser wants to become a PermUser you are reading his TempUser name to get his records as TempUser.
So now your job is easy. So now when a TempUser want to become PermUser all you would do is copy TempUser objects,populate your required attributes and create a new PermUser object with it. After that you can keep your TempUser record if you want to or delete it.. :)
Also you would have a history how many of your TempUsers actually become permanent if you keep it and also know in what average time a TempUser becomes permanent.
I think you should do a manual deep clone. Not exactly a clone since you have to merge data from several tempUsers to a single permUser. You can use reflection and optionally annotations to automate the copy of information.
To automatically copy fields from an existing object to a new one you can follow this example. It is not a deep clone but may help you as starting point.
Class 'c' is used as reference. src and dest must be instances of 'c' or instance of subclases of 'c'. The method will copy the attributes defined in 'c' and superclasses of 'c'.
public static <E> E copyObject(E dest, E src, Class<?> c) throws IllegalArgumentException, IllegalAccessException{
// TODO: You may want to create new instance of 'dest' here instead of receiving one as parameter
if (!c.isAssignableFrom(src.getClass()))
{
throw new IllegalArgumentException("Incompatible classes: " + src.getClass() + " - " + c);
}
if (!c.isAssignableFrom(dest.getClass()))
{
throw new IllegalArgumentException("Incompatible classes: " + src.getClass() + " - " + c);
}
while (c != null && c != Object.class)
{
for (Field aField: c.getDeclaredFields())
{
// We skip static and final
int modifiers = aField.getModifiers();
if ( Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers))
{
continue;
}
// We skip the fields annotated with #Generated and #GeneratedValue
if (aField.getAnnotation(GeneratedValue.class) == null &&
aField.getAnnotation(Generated.class) == null)
{
aField.setAccessible(true);
Object value = aField.get(src);
if (aField.getType().isPrimitive() ||
String.class == aField.getType() ||
Number.class.isAssignableFrom(aField.getType()) ||
Boolean.class == aField.getType() ||
Enum.class.isAssignableFrom(aField.getType()))
{
try
{
// TODO: You may want to recursive copy value too
aField.set(dest, value);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
c = c.getSuperclass();
}
return dest;
}
Like some have already suggested I would tackle this problem using inheritance + either shallow copies (to share references) or deep cloning with libraries that let me exclude / manipulate the auto-generated ids (when you want to duplicate items).
Since you don't want to bend your database model too much, start with a Mapped Superclass with common attributes. This will not be reflected in your database at all. If you could I would go with Single Table Inheritance which maps close to your model (but may require some adjusts on the database layer).
#MappedSuperclass
public abstract class User {
#Id
#GeneratedValue
private long id;
// Common properties and relationships...
Then have both PermUser and TempUser inherit from User, so that they will have a lot of common state:
#Entity
#Table(name="USER")
public class PermUser extends User {
// Specific properties
}
Now there are several possible approaches, if your classes don't have a lot of state, you can, for instance, make a constructor that builds a PermUser collecting data of a List of TempUsers.
Mock code:
#Entity
#Table(name="PERMANENT_USER")
public class PermUser extends User {
public PermUser() {} // default constructor
public PermUser(List<TempUser> userData) {
final Set<Favorites> f = new LinkedHashSet<>();
// don't set the id
for(TempUser u : userData) {
this.name = u.getName();
// Shallow copy that guarants uniqueness and insertion order
// Favorite must override equals and hashCode
f.addAll(u.getFavorites());
}
this.favorites = new ArrayList<>(f);
// Logic to conciliate dates
}
}
When you persist the PermUser it will generate a new id, cascaded unidirectional relationships should work fine.
On the other hand, if your class have a lot of attributes and relationships, plus there are a lot of situations in which you really need to duplicate objects, then you could use a Bean Mapping library such as Dozer (but be warned, cloning objects is a code smell).
Mapper mapper = new DozerBeanMapper();
mapper.map(tempUser.getFavorites(), user.getFavorites());
With dozer you can configure Mappings through annotations, API or XML do to such things as excluding fields, type casting, etc.
Mock mapping:
<mapping>
<class-a>my.object.package.TempUser</class-a>
<class-b>my.object.package.PermUser</class-b>
<!-- common fields with the same name will be copied by convention-->
<!-- exclude ids and fields exclusive to temp
<field-exclude>
<a>fieldToExclude</a>
<b>fieldToExclude</b>
</field-exclude>
</mapping>
You can, for example, exclude ids, or maybe copy permUser.id to all of the cloned bidirectional relationships back to User (if there is one), etc.
Also, notice that cloning collections is a cumulative operation by default.
From Dozer documentation:
If you are mapping to a Class which has already been initialized, Dozer will either 'add' or 'update' objects to your List. If your List or Set already has objects in it dozer checks the mapped List, Set, or Array and calls the contains() method to determine if it needs to 'add' or 'update'.
I've used Dozer in several projects, for example, in one project there were a JAXB layer that needed to be mapped to a JPA model layer. They were close enough, but unfortunately I couldn't bend neither. Dozer worked quite well, was easy to learn and spare me from writing 70% of the boring code. I can deeply clone recommend this library out of personal experience.
From a pure OO perspective it does not really make sense for an instance to morph from one type into another, Hibernate or not. It sounds like you might want to reconsider the object model independently of its database representation. FourWD seems more like a property of a car than a specialization, for example.
A good way to model this is to create something like a UserData class such that TempUser has-a UserData and PermUser has-a UserData. You could also make TempUser has-a PermUser, though that's going to be less clear. If your application needs to use them interchangeably (something you'd get with the inheritance you were using), then both classes can implement an interface that returns the UserData (or in the second option, getPermUser, where PermUser returns itself).
If you really want to use inheritance, easiest might be to map it using the "Table per class hierarchy" and then using straight JDBC to update the discriminator column directly.
I got an application in GWT that will consist of a listbox with more than 50 items. When selecting one I'll go to the corresponding place.
To avoid hard coded values and to share with the server part, I created an Enum lets call it TableEnum
So Table Enum is composed of a key and a displayName.
Which I then use to fill my combo. Once the selection is done, I got the value and so need to get the Place to go to.
That's why I created a factory that take the value of the selection and return a Place object.
First solution I was about to do is transform my value in TableEnum object et do a switch/case creating the correct associated Place.
But I was also thinking about adding the Place directly as a field of my Enum. This would avoid the switch/case and I would only need to do tableEnum.getPlace().
But I'm not really confident that this can be called a good practice. In my head Enum were simple objects not really knowing what was around them.
Thanks for information
Enums in Java are not just a placeholder for integers, or just some constants (such as some languages). Enums are classes with fixed number of objects, so it is a good practice to give your enums more brain, and always forget about lots of if/else or *switch/case*es.
If each item in the enum is associated to only one place, you can create an abstract method on your enum to get the place.
public enum TableEnum {
FIRST(){
public Place getPlace(){ return new FirstPlace(); }
},
SECOND(){
public Place getPlace(){ return new SecondPlace(); }
};
public abstract Place getPlace();
}
Later, you can access the place like so:
TableEnum t = ...
t.getPlace()
like Danny Kirchmeier's, but maybe less code:
enum Table {
first(Place.place1), second(Place.place2);
Table(Place place) {
this.place = place;
}
final Place place;
}
maybe your place should be an enum?