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
Related
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.
I am now making a DiffUtil class to update only changed items in the RecyclerView.
I have seen several other sample code.
When comparing two objects, they compared unique values such as id defined in the Model(Data) class in areItemsTheSame().
However, I think it is difficult to assign an id or unique value to the List, or the code is messy.
Do I have to define and compare id like this?
Do I really need to define a unique Id variable in the Model class that separates each object?
Or shouldn't I use simply the equals()?
Using this Is it not just comparing the address of the object, but also the contents of the object?
As an additional question
What is the difference between DiffUtil.CallBack and DiffUtil.ItemCallBack?
This is my code.
RoutineModel.java
public class RoutineModel {
private ArrayList<RoutineDetailModel> routineDetailModels;
private String routine;
public RoutineModel(ArrayList<RoutineDetailModel> items, String routine) {
this.routine = routine;
this.routineDetailModels = items;
}
public ArrayList<RoutineDetailModel> getDetailItemList() {
return routineDetailModels;
}
public int getDetailItemSize() {
return routineDetailModels.size();
}
public String getRoutine() {
return routine;
}
public void setRoutine(String routine) {
this.routine = routine;
}
}
RoutineDiffUtil.java
public class RoutineDiffUtil extends DiffUtil.Callback {
private final List<RoutineModel> oldRoutineList;
private final List<RoutineModel> newRoutineList;
public RoutineDiffUtil(ArrayList<RoutineModel> oldRoutineList, ArrayList<RoutineModel> newRoutineList) {
this.oldRoutineList = oldRoutineList;
this.newRoutineList = newRoutineList;
}
#Override
public int getOldListSize() {
return oldRoutineList.size();
}
#Override
public int getNewListSize() {
return newRoutineList.size();
}
#Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldRoutineList.equals(newRoutineList);
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldRoutineList.equals(newRoutineList);
}
}
You got wrong the meaning of areItemsTheSame() and areContentsTheSame() callbacks. As you see, there are oldItemPosition and newItemPosition arguments in them. You should use them to compare specific items – not lists themselves.
In areItemsTheSame() you have to check whether model at "old" position in the old list equals a model at "new" position in the new list. This is how DiffUtil knows if it has to make reordering animations.
areContentsTheSame() will be called for two items if and only if you return true for them in the previous callback. Here you have to check whether visual representation of "old" and "new" models is the same. This is how DiffUtil knows if it has to make "item changing" animations.
To compare two models you have to override equals() and hashCode(). There you specify conditions under which you consider two models the same. For example, if they have same routine. I don't the know context of your task so I can't tell you exactly how to implement them, but usually you just compare all fields. Probably adding an id field is a good idea too. Then you can consider models "equal" if they have same id. And in hashCode() you can just return Objects.hash(id).
Now, speaking about your question about ItemCallback. Formally, here is the explanation from docs:
DiffUtil.Callback serves two roles - list indexing, and item diffing. ItemCallback handles just the second of these, which allows separation of code that indexes into an array or List from the presentation-layer and content specific diffing code.
Practically, ItemCallback just has less methods to implement and is used together with AsyncListDiffer. It's just because missing methods are already implemented under the hood in AsyncListDiffer.
You have to override the equals and hashcodes of your model classes.
RoutineModel:
class RoutineModel {
private ArrayList<RoutineDetailModel> routineDetailModels;
private String routine;
public RoutineModel(ArrayList<RoutineDetailModel> items, String routine) {
this.routine = routine;
this.routineDetailModels = items;
}
public ArrayList<RoutineDetailModel> getDetailItemList() {
return routineDetailModels;
}
public int getDetailItemSize() {
return routineDetailModels.size();
}
public String getRoutine() {
return routine;
}
public void setRoutine(String routine) {
this.routine = routine;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RoutineModel that = (RoutineModel) o;
return Objects.equals(routineDetailModels, that.routineDetailModels) &&
Objects.equals(routine, that.routine);
}
#Override
public int hashCode() {
return Objects.hash(routineDetailModels, routine);
}
}
RoutineDiffUtil:
public class RoutineDiffUtil extends DiffUtil.Callback {
private final List<RoutineModel> oldRoutineList;
private final List<RoutineModel> newRoutineList;
public RoutineDiffUtil(ArrayList<RoutineModel> oldRoutineList, ArrayList<RoutineModel> newRoutineList) {
this.oldRoutineList = oldRoutineList;
this.newRoutineList = newRoutineList;
}
#Override
public int getOldListSize() {
return oldRoutineList.size();
}
#Override
public int getNewListSize() {
return newRoutineList.size();
}
#Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldRoutineList.get(oldItemPosition).getRoutine().equals(newRoutineList.get(newItemPosition).getRoutine());
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldRoutineList.get(oldItemPosition).equals(newRoutineList.get(newItemPosition));
}
}
And don't forget to override the equals and hashcode of your RoutineDetailModel.
For a project, which generates XML-files based on a XSD-file, I want to automatically generate the documentation. *
In this documentation I list the different elements defined in the XSD.
And for each element I want to show an example of that element.
The problem is, that the XML-example might be quite long and contains a lot of children.
Therefore I want to shorten the example by:
limiting the shown depth
limiting the amount of elements in a list
For the root-element that example might look like the following:
<root>
<elements>
<element>...<element>
<element>...<element>
<element>...<element>
...
</elements>
</root>
My approach:
To generate classes from the XSD and to generate and validate the XML files I use JAXB.
But I could not figure out how to marshal a Non-Root element.
Therefore I am generating my examples with XStream.
To limit the XML-example I am trying to decorate the PrettyPrintWriter, but that seems to be quite cumbersome.
The two decorators can be seen in my answer.
I just did not expect to care about the internals of a library for such a (common?) feature.
Is there an easier way to do this? (I can also use another library than XStream, or none at all.)
*
My approach is influenced by Spring Auto Rest Docs
To limit the shown depth I created the following XStream WriterWrapper. The class can wrap for example a PrettyPrintWriter and ensures that the wrapped writer only receives the nodes above a given depth threshold.
public class RestrictedPrettyPrintWriter extends WriterWrapper {
private final ConverterLookup converterLookup;
private final int maximalDepth;
private int depth;
public RestrictedPrettyPrintWriter(HierarchicalStreamWriter sw, ConverterLookup converterLookup, int maximalDepth) {
super(sw);
this.converterLookup = converterLookup;
this.maximalDepth = maximalDepth;
}
#Override public void startNode(String name, Class clazz) {
Converter converter = this.converterLookup.lookupConverterForType(clazz);
boolean isSimpleType = converter instanceof SingleValueConverter;
_startNode(name, !isSimpleType);
}
#Override public void startNode(String name) {
_startNode(name, false);
}
#Override public void endNode() {
if (_isLessDeepThanMaximalDepth() || _isMaximalDepthReached()) {
super.endNode();
}
depth--;
}
#Override public void addAttribute(String key, String value) {
if (_isLessDeepThanMaximalDepth() || _isMaximalDepthReached()) {
super.addAttribute(key, value);
}
}
#Override public void setValue(String text) {
if (_isLessDeepThanMaximalDepth() || _isMaximalDepthReached()) {
super.setValue(text);
}
}
/**
* #param name name of the new node
* #param isComplexType indicates if the element is complex or contains a single value
*/
private void _startNode(String name, boolean isComplexType) {
depth++;
if (_isLessDeepThanMaximalDepth()) {
super.startNode(name);
} else if (_isMaximalDepthReached()) {
super.startNode(name);
/*
* set the placeholder value now
* setValue() will never be called for complex types
*/
if (isComplexType) {
super.setValue("...");
}
}
}
private boolean _isMaximalDepthReached() {
return depth == maximalDepth;
}
private boolean _isLessDeepThanMaximalDepth() {
return depth < maximalDepth;
}
}
To limit the lists, I tried, in a first attempt, to modify the XStream CollectionConverter. But this approach was not general enough because implicit lists do not use this converter.
Therefore I created another WriterWrapper which counts the consecutive occurrences of elements with the same name.
public class RestrictedCollectionWriter extends WriterWrapper {
private final int maxConsecutiveOccurences;
private int depth;
/** Contains one element per depth.
* More precisely: the current element and its parents.
*/
private Map < Integer, Elements > elements = new HashMap < > ();
public RestrictedCollectionWriter(HierarchicalStreamWriter sw, int maxConsecutiveOccurences) {
super(sw);
this.maxConsecutiveOccurences = maxConsecutiveOccurences;
}
#Override public void startNode(String name, Class clazz) {
_startNode(name);
}
#Override public void startNode(String name) {
_startNode(name);
}
#Override public void endNode() {
if (_isCurrentElementPrintable()) {
super.endNode();
}
depth--;
}
#Override public void addAttribute(String key, String value) {
if (_isCurrentElementPrintable()) {
super.addAttribute(key, value);
}
}
#Override public void setValue(String text) {
if (_isCurrentElementPrintable()) {
super.setValue(text);
}
}
/**
* #param name name of the new node
*/
private void _startNode(String name) {
depth++;
Elements currentElement = this.elements.getOrDefault(depth, new Elements());
this.elements.put(depth, currentElement);
Elements parent = this.elements.get(depth - 1);
boolean parentPrintable = parent == null ? true : parent.isPrintable();
currentElement.setName(name, parentPrintable);
if (currentElement.isPrintable()) {
super.startNode(name);
}
}
private boolean _isCurrentElementPrintable() {
Elements currentElement = this.elements.get(depth);
return currentElement.isPrintable();
}
/**
* Evaluates if an element is printable or not.
* This is based on the concurrent occurences of the element's name
* and if the parent element is printable or not.
*/
private class Elements {
private String name = "";
private int concurrentOccurences = 0;
private boolean parentPrintable;
public void setName(String name, boolean parentPrintable) {
if (this.name.equals(name)) {
concurrentOccurences++;
} else {
concurrentOccurences = 1;
}
this.name = name;
this.parentPrintable = parentPrintable;
}
public boolean isPrintable() {
return parentPrintable && concurrentOccurences <= maxConsecutiveOccurences;
}
}
}
The following listing shows, how the two classes can be used.
XStream xstream = new XStream(new StaxDriver());
StringWriter sw = new StringWriter();
PrettyPrintWriter pw = new PrettyPrintWriter(sw);
RestrictedCollectionWriter cw = new RestrictedCollectionWriter(pw, 3);
xstream.marshal(objectToMarshal, new RestrictedPrettyPrintWriter(cw, xstream.getConverterLookup(), 3));
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.
I am currently implementing custom events and listeners according to the code posted below. I have been told that this is a very dirty implementation and that this needs to be changed. However, i am very new to java and android and do not see what is wrong with the current implementation. The way i have it below works and seems to be doing everything i needed it too. I was wondering if some people could please take a look at my code and make some suggestions on what i should change and what i am doing wrong. Taking my example and modifying it so that i can see what your talking about would be greatly appreciated.
Thanks in advance!
/* SmartApp.java */
public class SmartApp extends Activity
{
private ConnectDevice cD = new ConnectDevice();
private DataRobot dR = new DataRobot();
private DataBuilder dB = new DataBuilder();
private DataSender dS = new DataSender();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.intro);
cD.addDataReceivedListener(new DataReceivedListener() {
#Override
public void dataReceivedReceived(DataReceivedEvent event) {
// TODO Auto-generated method stub
dR.analyzeData(event.getData());
}
});
dR.addDataAnalyzedListener(new DataAnalyzedListener() {
#Override
public void dataAnalyzedReceived(DataAnalyzedEvent event) {
// TODO Auto-generated method stub
dB.submitData(event.getData());
}
});
dB.addDataBuilderListener(new DataBuilderListener() {
#Override
public void dataBuilderReceived(DataBuilderEvent event) {
// TODO Auto-generated method stub
dS.sendData(event.getData());
}
});
}
}
/* ConnectDevice.java
* This class is implementing runnable because i have a thread running that is checking
* the contents of a socket. Irrelevant to events. */
public class ConnectDevice implements Runnable {
private List _listeners = new ArrayList();
private String data;
/* Constructor */
public ConnectDevice() {// does some socket stuff here, irrelevant to the events}
public void run() {// does some socket stuff here, irrelevant to the events}
public synchronized void addDataReceivedListener(DataReceivedListener listener) {
_listeners.add(listener);
}
public synchronized void removeDataReceivedListener(DataReceivedListener listener) {
_listeners.remove(listener);
}
private synchronized void fireDataReceivedEvent(String temp) {
DataReceivedEvent dRE = new DataReceivedEvent(this, temp);
Iterator listeners = _listeners.iterator();
while(listeners.hasNext()) {
((DataReceivedListener)listeners.next()).dataReceivedReceived(dRE);
}
}
public interface DataReceivedListener {
public void dataReceivedReceived(DataReceivedEvent event);
}
}
/* DataRobot.java */
public class DataRobot {
/* This class is for analyzing the data */
private List _listeners = new ArrayList();
private String data;
public boolean analyzeData(String temp) {
/* Analyze the data
* This function analyzes the data, as explained in the OP
* This function fires the analyzed data event when finished
* analyzing the data.
*/
data = temp;
fireDataAnalyzedEvent(data); // this fires the dataanalyzedevent
return true; //for now this will always return true
}
public synchronized void addDataAnalyzedListener(DataAnalyzedListener listener) {
_listeners.add(listener);
}
public synchronized void removeDataAnalyzedListener(DataAnalyzedListener listener) {
_listeners.remove(listener);
}
private synchronized void fireDataAnalyzedEvent(String temp) {
DataAnalyzedEvent dRE = new DataAnalyzedEvent(this, temp);
Iterator listeners = _listeners.iterator();
while(listeners.hasNext()) {
((DataAnalyzedListener)listeners.next()).dataAnalyzedReceived(dRE);
}
}
public interface DataAnalyzedListener {
public void dataAnalyzedReceived(DataAnalyzedEvent event);
}
}
/* DataBuilder.java */
public class DataBuilder {
private List _listeners = new ArrayList();
private String data;
public boolean submitData(String temp) {
/* Builds the data
* This function builds the data, as explained in the OP
* This function fires the databuilder data event when finished
* building the data.
*/
data = temp;
fireDataBuilderEvent(data); //firing the databuilder event when finished
return true;
}
public synchronized void addDataBuilderListener(DataBuilderListener listener) {
_listeners.add(listener);
}
public synchronized void removeDataBuilderListener(DataBuilderListener listener) {
_listeners.remove(listener);
}
private synchronized void fireDataBuilderEvent(String temp) {
DataBuilderEvent dRE = new DataBuilderEvent(this, temp);
Iterator listeners = _listeners.iterator();
while(listeners.hasNext()) {
((DataBuilderListener)listeners.next()).dataBuilderReceived(dRE);
}
}
public interface DataBuilderListener {
public void dataBuilderReceived(DataBuilderEvent event);
}
}
/* DataSender.java */
/* this class has no event, because it is done firing events at this point */
public class DataSender {
private String data;
public boolean sendData(String temp) {
data = temp;
return true;
}
}
Below here are the event objects for each event. I Have each of this defined in a separate file, not sure if that is good procedure or not.
/* DataReceivedEvent.java */
public class DataReceivedEvent extends EventObject{
private String data;
public DataReceivedEvent(Object source, String temp) {
super(source);
// TODO Auto-generated constructor stub
data = temp;
}
public String getData() {
// this function is just an accessor function
return data;
}
}
/* DataAnalyzedEvent.java */
public class DataAnalyzedEvent extends EventObject{
private String data;
public DataAnalyzedEvent(Object source, String temp) {
super(source);
// TODO Auto-generated constructor stub
data = temp;
}
public String getData() {
// this function is just an accessor function
return data;
}
}
/* DataBuilderEvent.java */
public class DataBuilderEvent extends EventObject {
private String data;
public DataBuilderEvent(Object source, String temp) {
super(source);
// TODO Auto-generated constructor stub
data = temp;
}
public String getData() {
// this function is just an accessor function
return data;
}
}
I would not say it is a "very dirty implementation". Using callbacks/observers/listeners is a good practice in my opinion.
When I write Android applications I like to layer it such that the "application" is plain old Java with no Android imports and could theoretically be used in a Swing app, a Java EE-based web site, etc. The "Android" part is strictly user interface.
What I use callbacks for is to allow the Android code to register interest in events that take place in the application. For example, in a Blackjack game, an Activity might call game.getDealer().playHand() to tell the application to perform the dealer hand play logic. As that logic executes in the application, events are fired like cardDrawn(card), cardFlipped(card), handTotalChanged(handTotal), etc. The Android part of the app listens to these and redraws things on the screen accordingly (but it knows nothing about Blackjack).
I actually just have my activities implement interfaces like CardListener, HandListener, etc. so they can receive the event directly (unlike how you do it), but your style isn't necessarily a bad way.
I agree with #SingleShot in theory, for the parts of your Android application that can be Android-agnostic, and so long as the overhead introduced by all the indirection layers does not slow the app down too much. IMHO, in many apps, there is relatively little that fits this description.
In another post, you proposed your above solution for one activity to communicate to another activity. In Android, activities aren't just some Java objects you can toss around willy-nilly. They are managed by the OS and have particular lifecycles. While the observer/observable pattern is quite delightful in some places, it is unsuitable where the observer/observable connection will create garbage collection problems. In particular, one activity cannot, and should not, be trying to hold some sort of listener interface on another activity.
Similarly, a clean observer/observable pattern may break down in the face of databases, threads, services, and other bits of Android reality.
So, in pure Java code, isolated from Android, what you have is probably OK. However, do not go around recommending it as solutions for Android-specific problems unless you know it will work for those Android-specific problems. And, when you start trying to make your code work in an Android app, please do not be shocked if you run into problems trying to make your textbook pattern implementation work within the constraints placed upon Android apps.