Instantiate Child Object with Parent config or 'downcast parent to child' - java

I am not sure what the best practice for downcasting from parent to child or creating a B (extends A) out of A is.
As an example I have two classes:
The parent one:
public class SoccerPlayer {
private String name;
private SoccerShoe shoe;
private SoccerJersey jersey;
/* ... */
}
And the child one:
public class Goalkeeper extends SoccerPlayer {
private GoalkeeperGlove glove;
/* ... */
}
Now a regular soccer player wants to be a Goalkeeper. What can I do? Obviously the following would not work:
SoccerPlayerArrayOfTeamA[0] = new SoccerPlayer("Robert");
/*... new career path ...*/
SoccerPlayerArray[0] = (Goalkeeper) SoccerPlayerArray[0]
But that is what I would say "I want to do"...
The new Instance of the child class (Goalkeeper) should have all variable configurations as the old Instance of the parent class (SoccerPlayer). (e.g. name, jersey ...)
Is there an OOP way to do that I do I have to set every variable manually as in the following?
/*... new career path ...*/
SoccerPlayer temp = SoccerPlayerArray[0]
SoccerPlayerArray[0] = new Goalkeeper(temp.getName());
SoccerPlayerArray[0].setJersey(temp.getJersey());

Checkout Decorator Design Pattern. E.g. Java IO classes.
When any object dynamically wants to change its behavior then you can wrap that object with the desired object. Like if C wants to become B then B should have a constructor which accepts C and then the methods in B should use C where ever appropriate. Best example is when FileInputStream wants to become BufferedInputStream you can just create BufferedInputStream by passing FileInputStream in its constructor but it does not need to copy properties of FileInputStream.

Add a copy constructor to Goalkeeper that accepts SoccerPlayer as an argument.

Related

Generic methods to read/write to file all classes that extend X

sorry if this is a duplicate question, but I'm getting kind of desperate to solve a problem for a school project (due date tomorrow).
I'm very new to Java and this project involves storing data from certain objects to a local repository and also reading the data from the repo.
The repository handler class is in one package and the objects are in another.
My problem is that I don't know how to make generic methods in the handler to be able to read and write any object that extends X.
For example, let's say I have Fruit.
Apple extends Fruit.
Orange extends Fruit.
Both have their own unique attributes that I need to write/read to/from a file.
I wanted to have a method like
ArrayList repo_reader(String filepath)
That reads from a file and returns Apples and Oranges.
The only way that I know how to do this is having a field in the file stating which type of fruit it is, reading it and throwing it to a switch case like
switch (fruit_type){
case "Orange":
Orange orange = new Orange(); orange.setOrangeSpecificAttribute("ble");
FruitBasket.add(orange);
case "Apple":
Apple apple = new Apple(); apple.setAppleSpecificAttribute("bla");
FruitBasket.add(apple);
But then the method wouldn't be generic. Everytime that someone creates a new Fruit class, they would have to also change the repo_handler methods accordingly. The same would also happen with the writing method.
I could have the Fruit classes all implement their own method to write and read, but I don't want that. I want repo_handler class to deal with all the file reading and writing.
Again, sorry if it's a stupid question, and thanks for your guys' attention!
Btw, it's a CSV file, forgot to mention.
You may want to have different readers/factories dependending on the contents of some String. That is, the String acts as identifier for the reader/factory to use.
You can use a map to map identifiers (keys) to readers/factories (values). As the latter must be registered, I'd use the service loader mechanism as described in ServiceLoader, and iterate over all services to register them in this map.
Having this, you can look up the needed reader/factory in the map and use it to read/create new Fruit instances.
Step #1: Service Provider Interface
package com.mycompany.fruit;
public interface FruitFactory {
String getIdentifier();
Fruit createFruit(String[] attributes); // change params to your needs
}
Step #2: Service implementation
package com.mycompany.fruit;
public class AppleFactory implements FruitFactory {
public String getIdentifier() { return "Apple"; }
public Fruit createFruit(String[] attributes) {
Apple apple = new Apple();
apple.setCommonAttribute(attributes[1]);
apple.setSpecificAttribute(attributes[2]);
// ...
return apple;
}
}
Step #3: Register factories
Put a file com.mycompany.fruit.FruitFactory in META-INF/services. Put the fully qualified class name of each implementation of FruitFactory on separate lines in this file. For example:
com.mycompany.fruit.AppleFactory
com.mycompany.fruit.OrangeFactory
...
Step #4: Load the services and use them
public class MyFruitReader {
Map<String, FruitFactory> factories;
public MyFruitReader(...) {
ServiceLoader<FruitFactory> loader = new ServiceLoader(FruitFactory.class);
for (FruitFactory factory : loader) {
factories.put(factory.getIdentifier(), factory);
}
// usage
private Fruit getFruit(String[] row) {
String fruitType = row[0];
FruitFactory factory = factories.get(fruitType);
if (factory == null) {
return null;
}
return factory.createFruit(row);
}
// read the CSV file and call getFruit()
// ...
Keep in mind, that this are just sketches to provide a rough overview of this topic. You'll have to adapt it to your needs, add exception handling, fix errors, and so on.

Creating child objects on basis created parent object in java

I'm learning java design patterns and I wonder if I can apply some with following problem. I have class Solider and some child classes, for example: General and Sergeant. I'm creating Solider object and in runtime I want to change this object to General or Sergeant object, or create new Sergeant or General object using created earlier Solider object:
Solider s = new Solider(...);
.....
if (generalCondition) {
General g = createGeneralFromSolider(s);
//or better:
//General g = promoteSoliderToGeneral(s);
} else if (sergeantCondition) {
Sergeant sr = createSergeantFromSolider(s);
//or better:
//Sergeant sr = promoteSoliderToSergeant(s);
}
Firstly I decided to create additional constructor in General/Sergeant Class:
Class General extends Solider {
General(Solider s, Map<String, String> generalSpecificParams) {
//first we are going to copy all solider params to general params (bad idea if we have a lot of params)
this.setParamX(s.getParamX());
....
//then we can assign the rest of general-specific params
this.setGeneralSpecificParams(generalSpecificParams);
}
}
and use it in methods createGeneralFromSolider but I'm not sure if it is elegant way. Main disadvantage is that I create new object, so after calling createGeneralFromSolider I have 2 object in memory. I would rather have one object in memory: General/Sergeant promoted from Solider (object General/Sergeant which earlier was the Solider object). I wonder if I can use some design patter to resolve it. I remember that in C++ there has been something like copying constructors which copying all params from one object to another by assigning all params, one after another. In Java I didn't hear about anything similar.
You would probably need to use a Factory pattern for this kind of situation.
For example:
public class SoldierFactory {
//use getSoldier method to get object of type Soldier
public Soldier getSoldier(String soldierType){
if(soldierType == null){
return null;
}
if(soldierType.equals("case1")){
return new General();
} else if(soldierType.equals("case2")){
return new Sergeant();
} else if(.....
}
return null;
}
}
public class FactoryPatternDemo {
public static void main(String[] args) {
SoldierFactory soldierFactory = new SoldierFactory();
Soldier s1 = soldierFactory.getsoldier("case1");
}
}
I think its better to not create the Soldier ahead of calling Soldier factory. You're going to change it regardless during run-time right?
First of all, when constructing child classes, use super as the first statement of the constructor like so:
class Soldier {
private String rank; // e.g. Pvt, PFC, etc.
private int yearsOfService;
// ... (Standard constructor)
public Soldier(Soldier s) {
this.rank = s.rank; this.yearsOfService = s.yearsOfService;
}
// ... (Getters and Setters)
}
class Sergeant extends Soldier {
private int subordinates;
public Sergeant(Soldier s) {
super(s)
this.rank = "Sergeant"; // overwrites this Sergeant's rank
this.subordinates = 0;
}
}
You could easily encapsulate this in a promoteSoldierToSergeant method. However, this can lead to telescoping constructors if classes with many attributes are designed naively, or necessitate your map-based workaround. To resolve this, I'm personally a big fan of the Builder pattern, but you can also consider the Factory pattern.
Your question regarding "copying constructors" is perhaps best addressed by reading up on the Clonable interface, but be aware of the differences between shallow and deep copies, and the implications for your classes and data structures.
I think your approach is totally acceptable. If you have an object X, that you want to turn into Y, you can do it in Y constructor, copying all necessary fields.
You could as well use a builder, or static factory methods, but either way you'll have to copy fields, as there's no automatic copy constructor in java (except if you use some dedicated library such as lombok, which can provide full-args constructors from annotations)
You worry about having 2 objects in memory. But if you remove every reference of the original Soldier, the garbage collector will destroy it.
Last thing, as mentionned by #tsolakp , is it a good design to have General inheriting from Soldier? Couldn't it be just a "grade" variable, or something like that, to reflect this state? It's a common mistake to overuse inheritance where composition would be sufficient, and would cause less troubles.
What you want could be achieved using Reflections.
That way you can automatically copy fields from the instance of parent to child class.
Your code would look something like this:
public static void copyObject(Object src, Object dest)
throws IllegalArgumentException, IllegalAccessException,
NoSuchFieldException, SecurityException {
for (Field field : src.getClass().getFields()) {
dest.getClass().getField(field.getName()).set(dest, field.get(src));
}
}
public static General createGeneral (Solider solider, String devision) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
General general = new General();
copyObject(solider, general);
general.setDevision(devision);
return general;
}
The Field import is java.lang.reflect.Field;
========================================================================
Another way would be to use the Apache Bean Utils.
Than, you can use it's cloneBean(Object Bean) method like this:
General general = cloneBean(solider);
to copy the fields from solider to general and after that all the fields that are specific to child class (General).
========================================================================
EDIT: It would also be wise to introduce another child class that would be used for "ordinary" soliders if you intended to use the parent class Solider for "ordinary" soliders (which I suppose you do according to your commented method name promoteSoliderToGeneral(Solider s).
So, for example you would have a parent class called MilitaryMan and 3 child classes that extend it: Solider, General and Sergeant.
This way, you can uniformly handle all of the MilitaryMan. And, you can check if the MilitaryMan is a Solider, General or Sergeant with:
if (militaryMan instanceOf Solider) {
// do solider specific processing
...
} else if (militaryMan instanceof General) {
...
} else if (militaryMan instanceof Sergeant) {
...
}
I think it would be cleaner this way.

Java cast base class to an extended class

i have a class that is used widely in my project as some sort of field holder. Something like:
class A
{
private String field = null;
private String field2 = null;
private String field3 = null;
// and its generic Getters and Setters
}
In certain part of code i need add additional fields to this class. So i did this
class B extends A
{
private String fieldInB = null;
// and its Getters and Setters
}
in my function i thought i could easily do
public void foo( A a )
{
B b = (B)a;
}
And i could have all the fields written in aobject and i could easily set only field in b and use it. This seams like a common problem, but i just don't know how to do it except with an very ugly approach:
public B( A a )
{
// copy all the fields one at the time
}
You areconfusing different parts of Java:
B b = (B)a;
this is classical class cast, but to work with B class object you need:
1. be sure that a is of B class (check it with instanceof java keyword:
if (a instanceof B) {
B b = (B) a;
}
2. or wrap a in B class object (create B class object with copying fields from a).
PS in most of Java coding conventions it is recommended to fill fields by concrete values only (and not fill with default JavaVM values - nulls)
Comfortable way to copy A class fields to new instance:
public A (A a) {
this.field = a.field;
this.field2 = a.field2;
this.field3 = a.field3;
}
and for B class:
public B (A a) {
super(a);
}
Another way - some libraries that will work with A class and B class as with beans. Sample of this libraries you can find in Toilal's answer
You could use Dozer. It allows to map bean property values from one bean class to another.
Hai john Actually i didn't get your exact requirement. I recon the way you have written this code is not right.
Private variable cant be inherited.If you need to extend values to your subclass you should have declared those variables as public.
public B(A a)
{
super.field=a.field;
super.field2=a.field2;
super.field3=a.field3;
}

Accessing current object's sibling method

I have two (sibling) classes, both is subclass of the same parent. Parent contains all the methods that is shared by the two sibling, and the sibling classes contain only methods that are not shared and has different implementations.
Example,
class Parent() {
}
class Sibling1 extends Parent() {
byte[] sharedSecret;
int sharedSecretLength;
public generateKey() {
sharedSecret = keyAgree.generateSecret());
sharedSecretLength = sharedSecret.length);
}
}
class Sibling2 extends Parent() {
byte[] sharedSecret2;
int sharedSecretLength2;
public generateKey() {
sharedSecret2 = new byte[sharedSecretLength];
sharedSecretLength2 = keyAgree.generateSecret(sharedSecret2, 0);
}
public int getSharedSecretLength() {
return sharedSecretLength();
}
}
As you can see, both contains same method but implemented differently. My question is, if objects of both class (sibling1 and sibling2) are created AND obj2 generateKey to be generated successfully depends on sharedSecretLength of obj1. Example,
Parent obj1 = new Sibling1();
Parent obj2 = new Sibling2();
obj1 is instantiated in different class (Server class that I created) and obj2 in different class (Client that I created). If obj1 invoke it's own generateKey --> ((Sibling1)obj1).generateKey(), how can I use use getSharedSecretLength on the same object (obj1) to relay the needed information over to obj2's generateKey to generate successfully? I tried something like (in obj2's generateKey() ):
sharedSecret2 = new byte[Sibling1.sharedSecretLength];
...and it didn't work. Creating Sibling1 obj1 inside of Sibling2 class and then call it that way, for example,
Sibling1 xx = null;
.
.
sharedSecret2 = new byte[((Sibling1)xx).sharedSecretLength];
doesn't work because xx is new object. I am trying to use the old obj in which it generated it's key and contains sharedSecretLength that is not 0
If both obj1 and obj2 were created in the same class, it would have been easier.
Please help point me to the right direction
Instead of
((Sibling1)xx).sharedSecretLength
call it like
((Sibling1)xx).getSharedSecretLength()
In java, you have pass the empty parenthesis if it doesn't accept parameter and it doesnt work by field name, you will have to give the same method name as to what you have defined.
It sounds like you should refactor like this so that the generateKey method on Sibling2 has the argument it requires:
Sibling1 obj1 = new Sibling1();
obj1.generateKey();
Siblibg2 obj2 = new Sibling2();
obj2.generateKey(obj1.getSharedSecretLength());

Can a subclass be instantiated from an already instantiated superclass?

So I have a super class and I want to instantiate multiple sub classes off of it. The sub classes will probably be multi-threaded.
E.g.:
public class Person() {
protected variables;
public/private methods ect.
}
public class Man() extends Person {
private variables;
public/private methods;
}
public class Woman() extends Person {
private variables;
public/private methods;
}
I want to instantiate Person then extend Man and Woman classes off of it.
Like:
Person A = new Person();
Man B = //some how extends A;
Woman C = //some how extends A;
Or are there other ways of achieving the same goal?
You are misunderstanding the difference between a class and an object. A class is the overall definition of how an object will be composed. An object is a specific instance.
So if you create an instance of Person then that's just that a single object instance of the Person class. You can't extend it dynamically to have it as a Man at runtime (there are patterns where you could sort of do this, but not inheritance). If you want a Man you have create an instance of one.
Maybe your real question is different. Maybe you want to use an instance of Person as the template to create new instances of Man and Woman.
Imagine this
class Person {
private String name;
public Person(String name) { ... }
}
and a prototype person:
Person kelly = new Person ("Kelly");
Maybe you want to make a copy of the generic "kelly" as a Man and as a Woman - two separate objects, that happen to have this gender-neutral name in common
Man kellyMan = new Man(kelly);
Woman kellyWoman = new Woman(kelly);
What are we seeing above? We're seeing a copy constructor pattern. The contents of the original Person object could be copied into a new Man or Woman object which would then go on to live lives of their own. Example:
class Man : extends Person {
public Man(Person template) {
super(template); // pass to superclass for copying
}
}
class Person {
...
public Person(Person template) {
this.name = template.name;
// etc
}
}
This is not an uncommon way to go about things. Dynamically changing the type of objects at runtime is not common at all... I tried it once. Don't do it!
If you want to inherit a class:
public class Child extends Parent { ...
You can have multiple child classes that inherit from the same parent, you just can't inherit from more than one class. Here are some examples of what you can use. Remember, when you write something like Person p = new Person(), you have p which is a reference to a Person object. Try messing around with mixing up object types with different references, and see what happens.

Categories