Java abstract method object creation is bad? - java

I am programming a game for years now but I have a question about how I programmed things up.
So imagine you have a gun class for a game, guns can have many sprites, sounds, casings, projectiles, parameters, etc. So then I just need to create another class extending this gun class and fill my abstract methods up with what I need that particular gun to do.
So I made an abstract class to handle all of the internal code of the gun, if it shoots, if it needs bolt action and how long it has to wait, when to play the fire sound, etc. So basically the main gun class calls for the actual gun class (that is filled with abstract methods) for these parameters.
So my question is, if I am calling these abstract methods over and over again as needed throughout the code is it bad to have the following?
#Override
protected String getName() {
//This should be ok
return "Winchester";
}
#Override
protected boolean isBoltAction() {
//This should be ok
return false;
}
#Override
protected float getBoltActionTime() {
//This should be ok
return 0.5f;
}
#Override
protected Vector2 getPosOffset() {
//problem? or not?
return new Vector2(3,0);
}
If I call getPosOffset which I need it to be an Vector2 object for simplicity, the object itself shouldn't be too much expensive but would this create problems down the line? I ask because afaik even though the object itself doesn't change and is preset it is creating a new one everytime I call this method without really needing to, I could load a list and put everything there neatly without creating additional objects but that could make my abstract class kinda useless atleast for these methods. Is it bad to do this and should I change this? I've tried to see how many nanoseconds it takes if I load it up in a field vs this way and I saw no significant expense on time.
The game is running smoothly though but I am just not sure if my ocd is acting up or there is something problematic here.
UPDATE:
protected void update() {
//get position of player
pos.x = (float) (LevelManager.getPlayer().getPos().x);
pos.y = (float) (LevelManager.getPlayer().getPos().y);
//Tweener stuff to animate the recoil
posOffset.x = recoilTweener.tick();
//Fire time check
if (timePassed >= this.salvoDelay) {
//fire only if:
//if its automatic then allow it
//And
//if not needsBoltAction and we haven't "reloaded" the boltaction, these are Firearm fields not properties
//and
//if mouse left button is pressed
if (((this.automatic || !shooted) && (!needsBoltAction && !boltActionActive)) && Gdx.input.isButtonPressed(Buttons.LEFT)) {
//prevents hold firing for non automatic weapons
shooted = true;
//Tells us that we should fire
firing = true;
} else if (!Gdx.input.isButtonPressed(Buttons.LEFT)) {
//If the left mouse button isn't held lets reset
shooted = false;
}
} else {
//if time hasn't passed lets wait
timePassed += Math.min(Gameloop.getFrameTime(), this.salvoDelay);
}
//If we can fire and it was triggered above
if (firing) {
//Set time for salvo, in the sense each salvo shoots x projectiles within a set amount of time in between
timePassed += Math.min(Gameloop.getFrameTime(), this.salvoDelay + this.shotsPerSalvo * this.shotDelay);
//if we have shots to fire
//and
//if timepassed is bigger than the current shot * shotDelay
if (this.shotsPerSalvo > shotsFired && timePassed - this.salvoDelay >= shotsFired * this.shotDelay) {
if (this.shotDelay == 0) {
//Create projectile and set it up
createProjectile(this.shotsPerSalvo);
//Since we have 0 shotDelay we set this to false and reset the gun
firing = false;
shotsFired = 0;
timePassed = 0;
//"Ask" properties if we need boltAction
needsBoltAction = this.boltAction;
} else {
//Create each individual shot according to the time
createProjectile(1);
//Increase shotsFired for calculations
shotsFired++;
}
//If shotsFired reached the shotsPerSalvo, again each salvo has x shots to be fired in an instant (example shotguns, glocks in burst mode)
} else if (shotsFired >= this.shotsPerSalvo) {
//Reset weapon
firing = false;
shotsFired = 0;
timePassed = 0;
//"Ask" properties if we need boltAction
needsBoltAction = this.boltAction;
}
}
//BoltAction logic
//If needsBoltAction was triggered and we press R "reload" and wait (boltActionTime)
if (needsBoltAction && Gdx.input.isKeyJustPressed(Keys.R)) {
//Doing boltaction
boltActionActive = true;
//We dont need to press R again
needsBoltAction = false;
}
//We are doing the boltAction and not firing the gun
if (boltActionActive && !firing) {
//Add time
//Remember that timePassed was reset when all shots were fired on a salvo, in any situation
timePassed += Math.min(Gameloop.getFrameTime(), this.boltActionTime);
//If time was enough
if (timePassed >= this.boltActionTime) {
//We can shoot again since boltAction is done
boltActionActive = false;
timePassed = 0;
}
}
}
private void createProjectile(int amount) {
if (amount <= 0) {
Console.write(new Color(1,0,0,1),"Error: Projectile amount is invalid!");
}
if (getFireSoundFile() != null) {
getFireSoundFile().play();
}
if (this.casing != null) {
for (int i = 0; i < this.casingsPerSalvo; i++) {
ParticleManager.add(createCasing());
}
}
recoilTweener.reset();
for (int i = 0; i < amount; i++) {
Projectile p = createProjectile();
p.setup(LevelManager.getPlayer().getPos().x + (float) (Math.cos(Math.toRadians(WeaponManager.angle)) * this.shotStartingPosOffset.x + Math.sin(Math.toRadians(WeaponManager.angle)) * this.shotStartingPosOffset.y), LevelManager.getPlayer().getPos().y + (float) (Math.sin(Math.toRadians(WeaponManager.angle)) * this.shotStartingPosOffset.x + Math.cos(Math.toRadians(WeaponManager.angle)) * this.shotStartingPosOffset.y), WeaponManager.angle + Utils.getRandomFloat(this.spread,true));
WeaponManager.addProjectile(p);
}
}
private Casing createCasing() {
return new Casing(this.casing, this.pos);
}
private Projectile createProjectile() {
return new Projectile(this.projectile);
}
At the moment I have the properties read as so:
protected Firearm() {
loadParameters();
//other stuff
}
/**
* Loads all guns parameters from the abstract methods
* This is to only load these methods only once
*/
private void loadParameters() {
this.casing = getCasing();
this.magazineDrop = getMagazineDrop();
this.casingsPerSalvo = getCasingsPerSalvo();
this.unlimitedAmmo = hasUnlimitedAmmo();
this.projectile = getProjectile();
this.projectileDamage = getProjectileDamage();
this.spread = getSpread();
this.shotsPerSalvo = getShotsPerSalvo();
this.salvoDelay = getSalvoDelay();
this.shotDelay = getShotDelay();
this.automatic = isAutomatic();
this.fireSound = getFireSound();
this.reloadSound = getReloadSound();
this.name = getName();
this.boltAction = isBoltAction();
this.boltActionTime = getBoltActionTime();
this.shotStartingPosOffset = getShotStartingPosOffset();
this.recoilOffset = getRecoilOffset();
}
/**
* Gets bullet casing sprite
*/
protected abstract Casing getCasing();
protected Casing casing;
/**
* Gets magazine object
*/
protected abstract Magazine getMagazineDrop();
protected Magazine magazineDrop;
/**
* Number of casing drops per salvo
*/
protected abstract int getCasingsPerSalvo();
protected int casingsPerSalvo;
/**
* If the weapon has unlimited ammo
*/
protected abstract boolean hasUnlimitedAmmo();
protected boolean unlimitedAmmo;
/**
* Projectile texture path
*/
protected abstract Projectile getProjectile();
protected Projectile projectile;
/**
* Projectile Damage
*/
protected abstract float getProjectileDamage();
protected float projectileDamage;
/**
* Angle spread, angle added to each shot
*/
protected abstract float getSpread();
protected float spread;
/**
* Shots fired per salvo
*/
protected abstract int getShotsPerSalvo();
protected int shotsPerSalvo;
/**
* Not to be confused with getShotDelay
* This is the delay per salvo (each salvo will fire a number of shots)
*/
protected abstract float getSalvoDelay();
protected float salvoDelay;
/**
* Delay per shot on a salvo
*/
protected abstract float getShotDelay();
protected float shotDelay;
/**
* If true then the pistol is automatic, if false the pistol is semi-automatic
*/
protected abstract boolean isAutomatic();
protected boolean automatic;
/**
* If true then the pistol is automatic, if false the pistol is semi-automatic
* Note: this should only return the name of the file+extension, the file will be looked up in the internal folder "sounds/sfx/weapons/fire"
*/
protected abstract String getFireSound();
protected String fireSound;
/**
* If true then the pistol is automatic, if false the pistol is semi-automatic
* Note: this should only return the name of the file+extension, the file will be looked up in the internal folder "sounds/sfx/weapons/fire"
*/
protected abstract String getReloadSound();
protected String reloadSound;
/**
* Weapon's name
*/
protected abstract String getName();
protected String name;
/**
* If true then player will need to press R to reload
*/
protected abstract boolean isBoltAction();
protected boolean boltAction;
/**
* Time of bolt action
*/
protected abstract float getBoltActionTime();
protected float boltActionTime;
/**
* Firearm's bullet starting position offset
* Will automatically rotate angle
*/
protected abstract Vector2 getShotStartingPosOffset();
protected Vector2 shotStartingPosOffset;
/**
* Firearm's recoil in units to be subtracted to the weapons default offset position
* Will make the firearm go backwards and fowards with a tweener according to the units
* I am putting a vector2 just incase I need the firearm to recoil in the y vector but I atm dont see any use
*/
protected abstract Vector2 getRecoilOffset();
protected Vector2 recoilOffset;
Just incase you need the properties:
public class Winchester extends Firearm {
public Winchester() {
super();
}
#Override
public String getSprite() {
return "winchesterwh.png";
}
#Override
public String getSpriteDropped() {
return null;
}
#Override
protected Casing getCasing() {
return new Casing("sprites/weapons/casing/smallcasing.png", new Vector2(0,0));
}
#Override
protected Magazine getMagazineDrop() {
return null;
}
#Override
protected int getCasingsPerSalvo() {
return 1;
}
#Override
protected boolean hasUnlimitedAmmo() {
return false;
}
#Override
protected Projectile getProjectile() {
return new Projectile("sprites/weapons/projectiles/bullet.png", new Vector2(2,20), 50f, 0f, getProjectileDamage());
}
#Override
protected float getProjectileDamage() {
return 10f;
}
#Override
protected float getSpread() {
return 1f;
}
#Override
protected int getShotsPerSalvo() {
return 5;
}
#Override
protected float getSalvoDelay() {
return 0.25f;
}
#Override
protected float getShotDelay() {
return 0.25f;
}
#Override
protected boolean isAutomatic() {
return false;
}
#Override
protected String getFireSound() {
return "sniperShot.ogg";
}
#Override
protected String getReloadSound() {
return null;
}
#Override
protected String getName() {
return "Winchester";
}
#Override
protected boolean isBoltAction() {
return false;
}
#Override
protected float getBoltActionTime() {
return 0.5f;
}
#Override
protected Vector2 getPosOffset() {
return new Vector2(3,0);
}
#Override
protected Vector2 getShotStartingPosOffset() {
return new Vector2(0,5);
}
#Override
public float getDamage() {
return 0;
}
#Override
public Vector2 getRecoilOffset() {
return new Vector2(3,0);
} } // cant seem to get this bracket to behave
I think a solution for this were EVERYONE would be happy is if I used XML to load the properties instead

If I got your design correctly, you have a base class GunBase like this:
public abstract class GunBase
{
public abstract String getImageFileName();
}
and implementations of that like this:
public final class Winchester extends GunBase
{
#Override
public final String getImageFileName() { return "Winchester.png"; }
}
If GunBase really contains only those getter methods, it should not be a class at all, but an interface.
If GunBase really provides functionality that is only parameterised by the return values of those getters, those getters should not be overridden at all; instead the base class should get attributes for the respective values:
public abstract class GunBase
{
private final String m_ImageFileName;
protected GunBase( final String imageFileName )
{
m_ImageFileName = imageFileName;
}
public final String getImageFileName() { return m_ImageFileName; }
}
A derived class would then look like this:
public final class Winchester extends GunBase
{
public Winchester()
{
super( "Winchester.png" );
}
}
Confessed, the parameter list for the protected constructor can get inconveniently long in this case, but this can be solved by using a map with all the values instead of discreet arguments.
Now only those methods remain abstract that describe a behaviour that is different for each gun (really different, not only a different value for a parameter).
But if a gun is in fact nothing else than a collection of values, you should think about why you designed your guns as a class tree, and not as a collection of a class Gun where each instance describes one weapon type.

This design contradicts one of the main OOP principles - Tell-Don't-Ask. I.e. instead of having code like this:
abstract class Gun {
public void fire() {
if (isBolt()) {
// do bolt specifics
} else if (isArrow()) {
// do arrow specifics
} else if (...)
}
}
you need to have code like this:
abstract class Gun {
abstract void fire();
}
class Bow extends Gun {
public void fire() {
// fire an arrow
}
}
class CrossBow extends Gun {
public void fire() {
// fire a bolt
}
}
Your primary motivation defined in the question is a GoF Template Method pattern, but note that it defines a skeleton for the whole processing and shouldn't have anything like if (type == "laser") mixins.
Generally common super-class should have only properties (fields/methods) which are truly common for all sub-classes. If you have there, say, boltActionTime which is used only by a single sub-class, that is wrong (and of course base class should know anything about sub-classes).

What I'm wondering is whether you're mixing up classes and instances. Let's say you have an AK-47. Regardless of how many AK-47s you have, they will all look and behave the same, except perhaps for some specialisations such as visors or different stocks.
This means that they are essentially constants. An AK-47 is not going to be a double-barrelled shotgun, after all. It's not going to fire arrows either.
What you need to do is see what is essentially different in terms of logic between your different guns. Because the rest are all properties. If there are only properties, you don't need subclasses.
If you're going to need more than one AK-47, you would simply have a list, all pointing to the same AK-47 instance.
Even if you have different behaviour, in the sense that it requires distinct code, between guns, chances are you can lump them into groups: shotguns, flintlock, fully automatic, etc. In that case, you only need classes for the differing behaviour.
It's the same with pets. You can have dogs, cats, hamsters, fish, whatever. But whether you have a British shorthair, a Persian, a Bengal or an ordinary street cat, they all say "meow" and have pointy ears. You don't need to implement "meow" for every breed of cat.

Following is mini version of your implementation with my suggestion:
public class Test {
public static void main(String[] arg) throws Exception{
Firearm gun = new Winchester();
gun.fire();
gun = new HenryRifle();
gun.fire();
}
}
class Winchester extends Firearm {
//as you are hard coding the values,
//the property belongs to the class Winchester
private static Vector2 wVec = new Vector2(1,2);
public Winchester() {
//if wVec was not static then use
//super.posOffset = wVec;
}
#Override
protected Vector2 getPosOffset() {
return wVec;
}
}
class HenryRifle extends Firearm {
private static Vector2 hVec = new Vector2(3,0);
#Override
protected Vector2 getPosOffset() {
return hVec;
}
}
abstract class Firearm {
Vector2 posOffset;
protected abstract Vector2 getPosOffset();
protected Firearm() {
this.posOffset = getPosOffset();
}
//all sub classes will inherit fire method
//no need to override it everywhere
public void fire() {
System.out.println("bang bang at " + posOffset);
}
}
record Vector2(int x, int y) {}
This outputs:
bang bang at Vector2[x=1, y=2]
bang bang at Vector2[x=3, y=0]
I think you need to separate logic from too much data:
Create something like **GunProps.getProperty("manchester", "posOffset")** to feed logic in the Firearm class. And if a gun has different behavior then override that method in sub class.
Performance hit won't be much for calling one method and retrieving data from Map of Maps.

Rumtime efficiency and abstraction/design are two different things. Like you said:
I could load a list and put everything there neatly without creating additional objects...
That brings runtime efficiency, however it doesn't make abstract class useless because there could also be various of strategies.
For example, when a bullet is fired, how do you calculate its trajectory? You can think of so many different strategies to make it funnier, and you will create more and more over time. If you mix these strategies in one method for all kind of guns, it will be hard to extend. The best option is to seperate them, to create abstraction.

Related

How to pass a classname as an argument java [duplicate]

In Java, how can you pass a type as a parameter (or declare as a variable)?
I don't want to pass an instance of the type but the type itself (eg. int, String, etc).
In C#, I can do this:
private void foo(Type t)
{
if (t == typeof(String)) { ... }
else if (t == typeof(int)) { ... }
}
private void bar()
{
foo(typeof(String));
}
Is there a way in Java without passing an instance of type t?
Or do I have to use my own int constants or enum?
Or is there a better way?
Edit: Here is the requirement for foo:
Based on type t, it generates a different short, xml string.
The code in the if/else will be very small (one or two lines) and will use some private class variables.
You could pass a Class<T> in.
private void foo(Class<?> cls) {
if (cls == String.class) { ... }
else if (cls == int.class) { ... }
}
private void bar() {
foo(String.class);
}
Update: the OOP way depends on the functional requirement. Best bet would be an interface defining foo() and two concrete implementations implementing foo() and then just call foo() on the implementation you've at hand. Another way may be a Map<Class<?>, Action> which you could call by actions.get(cls). This is easily to be combined with an interface and concrete implementations: actions.get(cls).foo().
I had a similar question, so I worked up a complete runnable answer below. What I needed to do is pass a class (C) to an object (O) of an unrelated class and have that object (O) emit new objects of class (C) back to me when I asked for them.
The example below shows how this is done. There is a MagicGun class that you load with any subtype of the Projectile class (Pebble, Bullet or NuclearMissle). The interesting is you load it with subtypes of Projectile, but not actual objects of that type. The MagicGun creates the actual object when it's time to shoot.
The Output
You've annoyed the target!
You've holed the target!
You've obliterated the target!
click
click
The Code
import java.util.ArrayList;
import java.util.List;
public class PassAClass {
public static void main(String[] args) {
MagicGun gun = new MagicGun();
gun.loadWith(Pebble.class);
gun.loadWith(Bullet.class);
gun.loadWith(NuclearMissle.class);
//gun.loadWith(Object.class); // Won't compile -- Object is not a Projectile
for(int i=0; i<5; i++){
try {
String effect = gun.shoot().effectOnTarget();
System.out.printf("You've %s the target!\n", effect);
} catch (GunIsEmptyException e) {
System.err.printf("click\n");
}
}
}
}
class MagicGun {
/**
* projectiles holds a list of classes that extend Projectile. Because of erasure, it
* can't hold be a List<? extends Projectile> so we need the SuppressWarning. However
* the only way to add to it is the "loadWith" method which makes it typesafe.
*/
private #SuppressWarnings("rawtypes") List<Class> projectiles = new ArrayList<Class>();
/**
* Load the MagicGun with a new Projectile class.
* #param projectileClass The class of the Projectile to create when it's time to shoot.
*/
public void loadWith(Class<? extends Projectile> projectileClass){
projectiles.add(projectileClass);
}
/**
* Shoot the MagicGun with the next Projectile. Projectiles are shot First In First Out.
* #return A newly created Projectile object.
* #throws GunIsEmptyException
*/
public Projectile shoot() throws GunIsEmptyException{
if (projectiles.isEmpty())
throw new GunIsEmptyException();
Projectile projectile = null;
// We know it must be a Projectile, so the SuppressWarnings is OK
#SuppressWarnings("unchecked") Class<? extends Projectile> projectileClass = projectiles.get(0);
projectiles.remove(0);
try{
// http://www.java2s.com/Code/Java/Language-Basics/ObjectReflectioncreatenewinstance.htm
projectile = projectileClass.newInstance();
} catch (InstantiationException e) {
System.err.println(e);
} catch (IllegalAccessException e) {
System.err.println(e);
}
return projectile;
}
}
abstract class Projectile {
public abstract String effectOnTarget();
}
class Pebble extends Projectile {
#Override public String effectOnTarget() {
return "annoyed";
}
}
class Bullet extends Projectile {
#Override public String effectOnTarget() {
return "holed";
}
}
class NuclearMissle extends Projectile {
#Override public String effectOnTarget() {
return "obliterated";
}
}
class GunIsEmptyException extends Exception {
private static final long serialVersionUID = 4574971294051632635L;
}
Oh, but that's ugly, non-object-oriented code. The moment you see "if/else" and "typeof", you should be thinking polymorphism. This is the wrong way to go. I think generics are your friend here.
How many types do you plan to deal with?
UPDATE:
If you're just talking about String and int, here's one way you might do it. Start with the interface XmlGenerator (enough with "foo"):
package generics;
public interface XmlGenerator<T>
{
String getXml(T value);
}
And the concrete implementation XmlGeneratorImpl:
package generics;
public class XmlGeneratorImpl<T> implements XmlGenerator<T>
{
private Class<T> valueType;
private static final int DEFAULT_CAPACITY = 1024;
public static void main(String [] args)
{
Integer x = 42;
String y = "foobar";
XmlGenerator<Integer> intXmlGenerator = new XmlGeneratorImpl<Integer>(Integer.class);
XmlGenerator<String> stringXmlGenerator = new XmlGeneratorImpl<String>(String.class);
System.out.println("integer: " + intXmlGenerator.getXml(x));
System.out.println("string : " + stringXmlGenerator.getXml(y));
}
public XmlGeneratorImpl(Class<T> clazz)
{
this.valueType = clazz;
}
public String getXml(T value)
{
StringBuilder builder = new StringBuilder(DEFAULT_CAPACITY);
appendTag(builder);
builder.append(value);
appendTag(builder, false);
return builder.toString();
}
private void appendTag(StringBuilder builder) { this.appendTag(builder, false); }
private void appendTag(StringBuilder builder, boolean isClosing)
{
String valueTypeName = valueType.getName();
builder.append("<").append(valueTypeName);
if (isClosing)
{
builder.append("/");
}
builder.append(">");
}
}
If I run this, I get the following result:
integer: <java.lang.Integer>42<java.lang.Integer>
string : <java.lang.String>foobar<java.lang.String>
I don't know if this is what you had in mind.
You should pass a Class...
private void foo(Class<?> t){
if(t == String.class){ ... }
else if(t == int.class){ ... }
}
private void bar()
{
foo(String.class);
}
If you want to pass the type, than the equivalent in Java would be
java.lang.Class
If you want to use a weakly typed method, then you would simply use
java.lang.Object
and the corresponding operator
instanceof
e.g.
private void foo(Object o) {
if(o instanceof String) {
}
}//foo
However, in Java there are primitive types, which are not classes (i.e. int from your example), so you need to be careful.
The real question is what you actually want to achieve here, otherwise it is difficult to answer:
Or is there a better way?
You can pass an instance of java.lang.Class that represents the type, i.e.
private void foo(Class cls)

How to add a item to player

I'm trying to add some custom ability to this plugin by using it own API. I have some trouble adding items to players when they got a kill. I have tried a lot of different methods to add potion to the killer by using .addItem(). There is no wiki for this plugin and on their page, there is some information about the API. Here is my code
public class ChemistryAbility extends Ability{
//Return name of ability
#Override
public String getName() {
return "Chemistry";
}
//Get the data form config file.
#Override
public void load(FileConfiguration file) {
// TODO Auto-generated method stub
}
//Get the activate Material
#Override
public Material getActivationMaterial() {
return null;
}
//Get the activate projectile
#Override
public EntityType getActivationProjectile() {
return null;
}
//Will this ability activate when player attack another player
#Override
public boolean isAttackActivated() {
return true;
}
//Will this ability activate when player get attacked by another player
#Override
public boolean isAttackReceiveActivated() {
return false;
}
//Will this ability activate when player get damage
#Override
public boolean isDamageActivated() {
return false;
}
//Will this ability activate when player interact with another player
#Override
public boolean isEntityInteractionActivated() {
return false;
}
#Override
public boolean execute(final Player p, final PlayerData PD, final Event e) {
ItemStack potion = new ItemStack(Material.SPLASH_POTION, 3);
PotionMeta pmeta = (PotionMeta) potion.getItemMeta();
pmeta.addCustomEffect(new PotionEffect(PotionEffectType.HARM, 1, 2), true);
potion.setItemMeta(pmeta);
Player killer = p.getKiller();
if (p.isDead()) {
p.getKiller();
if (p.getKiller() instanceof Player) {
killer.getInventory().addItem(potion);
}
}
return false;
}
}
K, So i don't know that much about plugin dev, but here is my best shot with 15 min of research. Not sure about the API, but if u can implement this outside the event, try this
#EventHandler
public void onKill(PlayerDeathEvent e) {
if (e.getEntity().getKiller() != null) { // to check if there was actually a killer
Entity killer = e.getEntity.getKiller(); // stores killer instance
if (killer.hasMetadata("Chemistry")) { // checks if has class
killer.getInventory().addItem(new ItemStack(Material.BOOK));
}
}
}
i think. i honestly dont know
Potions have always been a pain in Minecraft. Mojang changes how item data works.
I have some Deprecated code that I made. This should work for a few of the upcoming updates.
public ItemStack getPotionItem(Color c, PotionEffectType type, PotionType pType, boolean splash, int time, int level) {
Potion p = new Potion(pType);
p.setSplash(splash);
p.setType(pType);
ItemStack pot = new ItemStack(Material.SPLASH_POTION);
PotionMeta im = (PotionMeta) pot.getItemMeta();
List<String> lores = new ArrayList<String>();
lores.add(getLore());
im.setDisplayName(getName());
im.addCustomEffect(new PotionEffect(type, time, level - 1), true);
im.setLore(lores);
im.setColor(getColor());
im.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS);
im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
pot.setItemMeta(im);
p.apply(pot);
return pot;
}

How do I store a variable inside an interface to use?

I have an interface namely Medicine and I created few instances for that. let's have a look,
interface Medicine {
Medicine Antibiotic = new Medicine() {
#Override
public int getCountOfTuberculous(QuarantineTwo quarantineTwo) {
return quarantineTwo.tuberculous().getSize();
}
/**
* Antibiotic cures the tuberculous
*
* #param q
*/
#Override
public void on(QuarantineTwo q) {
int initialNumOfTuberculous = getCountOfTuberculous(q);
System.out.println("Numbe of perople have Tuberculous before treated w/ Antibiotic = " + initialNumOfTuberculous);
q.tuberculous().changeHealthStatus(q.healthy());
}
#Override
public Treatment combine(Treatment treatment) {
return treatment.plus(this);
}
#Override
public String toString() {
return "Antibiotic";
}
};
Medicine Insulin = new Medicine() {
// cant use this method as it will provide the number of Tuberculous 0
// because, initially, the Quarantine was treated with Antibiotic
#Override
public int getCountOfTuberculous(QuarantineTwo quarantineTwo) {
return quarantineTwo.tuberculous().getSize();
}
#Override
public void on(QuarantineTwo q) {
if (isInsulinCombinedWithAntibiotic(q.getTreatment())) {
q.healthy().changeHealthStatus(q.feverish());
// q.healthy().changeHealthStatus(q.feverish(), iniNumOfTuberculous);
} else {
// Prevent None effects, done is this.combine
}
}
#Override
public Treatment combine(Treatment treatment) {
return treatment.remove(Medicine.None)
.plus(this);
}
/**
* helper method to see whether the Insulin is combined with Antibiotic
*
* #param treatment
* #return
*/
private boolean isInsulinCombinedWithAntibiotic(Treatment treatment) {
return treatment.contains(this) &&
treatment.contains(Medicine.Antibiotic);
}
#Override
public String toString() {
return "Insulin";
}
};
void on(QuarantineTwo quarantineTwo);
Treatment combine(Treatment treatment);
int getCountOfTuberculous(QuarantineTwo quarantineTwo);
}
Now, when I'm testing I may call like this,
#Test
public void antibioticPlusInsulin() throws Exception {
quarantine.antibiotic();
quarantine.insulin();
assertEquals("F:3 H:1 D:3 T:0 X:0", quarantine.report());
}
The two lines of codes means that we combined the treatment procedures with both the antibiotic and insulin to the Quarantine system and affect should be accumulative.
quarantine.antibiotic();
quarantine.insulin();
And, hence, I would like to keep a track of how many people are cured with Antibiotic initially from the Tuberculous stored in the initialNumOfTuberculous and use that value to make the call
q.healthy().changeHealthStatus(q.feverish(), iniNumOfTuberculous);
This call suppose to change the all the people from healthy state to feverish but the ones initially cured with Tuberculous.
How to store the value of the iniNumOfTuberculous inside the Medicine Antibiotic and make it available in the Medicine Insulin ?
Sounds like you need an abstract class
abstract class AbstractMedicine implements Medicine {
protected int iniNumOfTuberculous;
}
public class Insulin extends AbstractMedicine {
// can use iniNumOfTuberculous here
}
Note: The availability of the variable definition is shared; the value itself is not.
I don't think you should implement your concrete classes inside an interface, by the way

Using instances of a class as reference

I need some help on my class design or better said a reference to a common design pattern for a problem.
I am working in the aircraft industry. So far my programming skills are VBA and basic JAVA applications.
As an engineer my task is to create CAD Models for fixating components in and on to aircraft kitchens. To ensure a high reusability and to reduce development time I want to create a program which can recommend previous solutions.
Basically each aircraft operator can select from a catalog which galleys/kitchens (Monument) it would like to have installed. Inside these Monuments are multiple compartments. Inside a compartment we can install multiple equipment’s/components.
I would like to write a program which can tell me "you have installed these components together before -> In this compartment -> in that aircraft for that customer"
I have modeled the compartment, the monuments, and the aircraft. Each class extends form the same class BaseHolder:
public abstract class BaseHolder <I> {
private final ArrayList <I> heldItems = new ArrayList<I>();
public boolean addItem(final I i){
Objects.requireNonNull(i, "cannot add NULL");
return heldItems.add(i);
}
public boolean removeItem(I i){
return heldItems.remove(i);
}
public boolean contains(I i){
return heldItems.contains(i);
}
public int itemCount(){
return heldItems.size();
}
public boolean isEmpty(){
return heldItems.isEmpty();
}
public void Clear() {
heldItems.clear();
}
protected List<I> getHeldItems(){
return heldItems;
}
public I getElement(int n){
return heldItems.get(n);
}
}
public class Aircraft extends BaseHolder<Monument> {
// code
}
public class Monument extends BaseHolder<Compartment> {
private String name;
public Monument (String name){
this.setName(name);
}
// code
#Override
public boolean addItem(final Compartment c) {
Objects.requireNonNull(c, "cannot add NULL");
if (contains (c) ){
throw new IllegalArgumentException("Compartment already added!");
};
for(Compartment ctmp : getHeldItems()){
if (ctmp.getName().equals(c.getName() ) ) {
throw new IllegalArgumentException("Compartment with an identical name already exits");
}
}
return getHeldItems().add(c);
}
public Compartment getCompartment(int n){
return getHeldItems().get(n);
}
public Compartment getCompartment(String name){
for(Compartment ctmp : getHeldItems()){
if (ctmp.getName().equals(name) ) {
return ctmp;
}
}
return null;
}
}
public class Compartment extends BaseHolder<IWeighable>{
private String name = "";
private double MAX_LOAD = 0.0;
public Compartment (String name ,final double max_load){
this.setName(name);
updateMaxLoad(max_load);
}
// code
protected double getTotalLoad(){
// code
}
/**
*
* #param load
* #throws InvalidParameterException if max load not >= than 0.0
*/
public void setMaxLoad(final double load){
if (load >= 0.0){
this.MAX_LOAD = load;
} else {
throw new InvalidParameterException("max load must be greater than 0.0");
}
}
public boolean isOverloaded(){
return (getTotalLoad() > MAX_LOAD ) ;
}
}
The problem I am having is that this design seems to have many flaws. Apart from it being rather tedious: getElement(n).getElement(n).getElement(n)
Adding elements to a compartment results in all aircrafts using the same compartment, having all the same equipment’s/components installed. As it is the same object in the DB. An instance of the compartment would be need. Cloning the DB Compartment before adding it to an aircraft is no option. I need to be able to change the allowable loads, a change it for all. To resolve this I thought of using some type of “wrapper” class as in:
public class MonumentManager {
public ArrayList <Monument> monuments = new ArrayList<>();
public ArrayList <LinkObect> links;
class LinkObect{
private Compartment c;
private IWeighable e;
LinkObect(Compartment c, IWeighable e){
this.c = c;
this.e = e;
}
}
public boolean addMonument(Monument m){
return monuments.add(m);
}
public void addElementToCompartment(IWeighable e, Compartment c){
boolean known = false; //to check if the passed compartment is known/handeld to/by the MonumentManager
for (Monument m : monuments){
if ( m.getCompartment(c.getName() ) != null ) known = true;
}
if (known){
links.add(new LinkObect(c, e));
} else {
throw new IllegalArgumentException("Compartment is not inside a managed Monument!");
}
}
public List<Compartment> whereUsed(IWeighable e){
// TODO
}
}
This class might solve the problem but it is feels odd. Can anybody point me in the right direction towards a common design pattern etc. I am reading a book from the local library on design patterns. But it seems to be slightly above me. (as is maybe my task).
Any suggestions / help etc would be highly appreciated.
I hope I'm understanding this correctly.
One thing is the Component you want to install that has certain characteristics and another thing is some representation of what you have installed.
The information of your installation does not need to be in your Component but in something else, let's call it Installation.
Your Installation has to know 2 things:
What kind of Component it is.
What other Installations it has inside.
The installation will look something like this.
public class Installation {
private Component type;
private List<Installation> content;
public Installation(Component type){
this.type = type;
this.content = new ArrayList<Component>();
}
//you can have methods for add, remove, etc...
}
Feel free to ask further clarifications.

Implementation of aggregator pattern in Java

[edit] Hmm, clearly I'm not asking this properly. Could you tell me why this is a bad question?
To put this differently, I want to find a why to implement what is define in this article as "Pure object aggregation" instead of "Object organized as a blob".
I'm doing my first attempt at implementing the aggregation pattern in Java.
At first glance Interfaces seems to be the answer, I ran into confusion when I needed default values for attributes.
Since constants are static, if I define anything in the interface it will be shared with every class that implements it. What I was going for was that I only need to implement this in cases when I wanted a value different from default.
Here an abstract class seems a better fit but I fall back to a multiple inheritance problem.
Here is the (impossible) skeleton I can up with:
public interface MenuItemPopup {
// Defaults
int windowHeight = 200;
int windowWidth = 350;
public void open();
public void setWindowHeight(int newHeight){
windowHeight = newHeight;
}
public void setWindowWidth(int newWidth){
windowWidth = newWidth;
}
}
public interface WindowButton {
// Defaults
Point size = new Point (5, 120);
public void initialize();
public void setSize(Point newSize){
size = newSize;
}
}
public class SomeFuncGUI extends MandatoryParentClass implements WindowButton, MenuItemPopup{
public void open(){
// do stuff
}
public void initialize(){
// do more stuff
}
}
public class OtherFuncGUI extends MandatoryParentClass implements MenuItemPopup{
public OtherFuncGUI(Point customPosition){
setSize(new Point(45, 92));
}
public void open(){
// do stuff
}
}
public class MainClass{
ArrayList <MandatoryParentClass> list = new ArrayList <MandatoryParentClass>();
list.add(new SomeFuncGUI());
list.add(new OtherFuncGUI());
for( MandatoryParentClass button : list){
// process buttons
if(button instanceof WindowButton){
button.open();
}
// process popups
if(button instanceof MenuItemPopup){
button.initialize();
}
}
}
I realise this doesn't compile.
How would I change this to implement aggregation pattern for MenuItemPopup and WindowButton?

Categories

Resources