The main objective is to avoid duplication of fields with best inheritance model on existing stuff:
I have following class hierarchy:
class A
{
private String fieldA1;
private String fieldA2
// getters and setters
}
Class B extends A
{
private String fieldB1;
private String fieldB2;
// getters and setters
}
A 'User' class will either extend A or B having its own fields.
Assume existing API's uses above data models.
Now there is a requirement to add new fields in Class A for new set of API's.
I have certain restriction not to modify existing data models since it exposes or breaks existing API's with these new fields . So new data models need to be created by extending existing ones such that new API's uses them with all existing fields + new fields. I have below solution which may not be the best approach as it adds duplication of fields.
class A
{
private String fieldA1;
private String fieldA2
// getters and setters
}
Class B extends A implements Common
{
private String fieldB1;
private String fieldB2;
// getters and setters
}
Class NewA extends A
{
private String fieldNewA;
// getters and setters
}
Class NewB extends NewA implements Common
{
private String fieldB1;
private String fieldB2;
private String fieldNewB;
// getters and setters
}
Interface Common
{
//marker interface
}
Please suggest if there is any better approach.
Thanks...
I think you need to take a step back and look at what is it that is causing you to keep adding new fields to your existing classes. Maybe you should just have one field which is a collection of property and values. This way any new field will just be another property/value in your collection. You won't have to then worry about adding new fields frequently.
Your example is not great, for example sub-classes cannot access private fields and it is not clear what you intend your subclasses to achieve.
If you wish to inherit state, your example should use either protected or public fields, or show getter and setter methods being inherited. When inheriting state, implementing an interface like Common is redundant. More detail may help clarify your intent.
That aside, yes you can extend your data models as you describe in order to add data types to an existing class. An example of wanting to do this might be wishing to create a Square class from a Triangle class, requiring adding a new point. And also requiring changing behaviour to make use of the new field.
Related
My question might not be useful but I really need to know why a lot of people creat new classes (Right-click, create new, class) but not use code to create a new class (for example: class task(var title:String, var time:String)).
I have never seen creating classes like that. Seems like you've mixed up functions with classes. Can you provide us any source where this way of creating classes is used?
lets says you very simple app with MainActivity.class
you want to add a new class.
you can do it in a separate file (right-click, create a new class) or in the MainActivity.class declare the class, for example
public class Car {
private String carModel;
private String carColor;
//constructor
public Car (String carModel, String carColor) {
this.carColor = carColor;
this.carModel = carModel;
}
//add setters and getters, methods and other stuff
This question already has answers here:
Immutable Type: public final fields vs. getter
(9 answers)
Closed 6 years ago.
Is it recommended to have public access modifiers for the data fields in final (Immutable) java class, even if the data fields are not the references to mutable datatype Or Shall we access data fields directly as data fields are supposed to be defined in constructor itself hence nullify all chances of changing the internal representation of class.
Please suggest?
For example:
public class MainApp {
public static void main(String args[]) {
Immutablesample immutablesample = Immutablesample.getInstance("akkhil");
System.out.println(" Before modification " + immutablesample.getName());
immutablesample.name = "gupta";
System.out.println(" After modification " + immutablesample.getName());
}
}
is the calling code trying to change the data field by accessing it directly(without access modifier) for the following class:
public final class Immutablesample {
private final String name;
private Immutablesample(String name){
this.name = name;
}
public String getName(){
return name;
}
public static Immutablesample getInstance(String name){
return new Immutablesample(name);
}
}
How would it make the class prone to get its internal representation changed if i change the modifier from private to public
private String name; to public String name;
since the object was creating with parameterized constructor so has immutable data fields, than why is it necessary to make data fields private?
Two simple rules to follow:
Try to make your whole class as "immutable" as you can. For example setting private final fields only via constructors. And when using "incoming" collection objects, consider to create a copy of their content to be really on the safe side.
Keep in mind that good OO is about exposing behavior; not about exposing data. Meaning: you absolutely do not want to make fields public unless you have really good reasons to do so. In other words: you do not want that some other class B does something because of the content of some field in class A. And the way to prevent that: making your fields private!
In general, it's a bad decision to show your inner presentation of a class, so it's much better if you hide even final immutable fields. You can only show such as fields if your class it's something like a tuple, where all members are used from outside.
Say I have a class which stores a weapon Arsenal
public class Arsenal{
List<RocketLauncher> rocketLaunchers;
List<HandGrenade> handGrenades;
List<LandMine> landMines;
//Followed by a few more weapons
}
The weapons are part of an enum, Weapon
Now, I am trying to display a summary screen or report elsewhere and I am preparing a map. See the snippet below. I have shown two approaches
public Map<Weapon,Integer> generateReport(Arsenal arsenal){
Map<Weapon,Integer> weaponCountMap = //suitable map impl
//Technique 1
//Create and use a larger num of getters from the Arsenal Class
weaponCountMap.put(Weapon.HAND_GRENADE, arsenal.getHandGrenades);
//.. and so on
//Technique 2
//Create a single method in Arsenal which returns a Map
weaponCountMap = arsenal.getSummary();
return weaponCountMap;
}
Question : Is it just me or does everyone feel 'not right' to use a large number of getters. Suppose Arsenal stores around 50 weapons, it's like 50 methods in the class. Double with setters.
Also. I feel less flexible using the 2nd method, with no accessor methods.
Can you guys please critically evaluate both approaches and possibly suggest new ones?
How about not hard-coding types of weapon inside of your Arsenal? The following is simple implementation of heterogeneous container for your specific case. However, as I don't quite familiar with Generics in enum, this implementation is when you have Weapon and their subclasses, e.g. HardGrenade extends Weapon, etc.
public class Arsenal{
private Map<Class<?>, Collection<?>> weaponArsenal;
public <T extends Weapon> Collection<T> get(Class<T> weaponClass) {
if (weaponArsenal.containsKey(weaponClass) {
return (Collection<T>) weaponArsenal.get(weaponClass);
}
return new ArrayList<T>(); // to avoid checking null everytime in client code
}
public <T extends Weapon> void put(T weapon) {
if (!weaponArsenal.containsKey(weapon.class)) {
Collection<T> weaponList = // initialize correct collection here
weaponArsenal.put(weapon.class, weaponList);
}
weaponArsenal.get(weapon.class).add(weapon);
}
}
and in the client code
Arsenal arsenal = new Arsenal();
arsenal.put(new HandGrenade());
arsenal.put(new RocketLauncher());
Collection<HandGrenade> handGrenades = arsenal.get(HandGrenade.class);
Collection<RocketLauncher> rocketLaunchers = arsenal.get(RocketLauncher.class);
In the arsenal you can duplicate the map instead of using lists. Then in the generateReport method you can iterate over the enum and use the enum value to get the suitable list from the map.
Something like
Arsenal:
Map<Weapon,List<Weapon>> weaponsMap;
arsenalMap.put(Weapon.HAND_GRENADE,handGrenades);
generate report:
for (Weapon weapon: Weapon.values()) {
weaponCountMap.put(Weapon.HAND_GRENADE, arsenal.weaponsMap.get(weapon));
}
Might not be the best solution but you will remove some of the getters.
If you make Arsenal immutable and construct it using a builder (to avoid having a bunch of constructors), you can make the instance variables public.
This approach allows you to use technique 1 from your question but without getters, and still keep state management of the object internal to the object.
public class Arsenal {
public final List<RocketLauncher> rocketLaunchers;
public final List<HandGrenade> handGrenades;
public final List<LandMine> landMines;
//Followed by a few more weapons
private Arsenal(final Arsenal.Builder builder) {
this.rocketLaunchers = Collections.unmodifiableList(builder.rocketLaunchers);
this.handGrenades = Collections.unmodifiableList(builder.handGrenades );
this.landMines= Collections.unmodifiableList(builder.landMines);
// and so on
}
public static class Builder {
private final List<RocketLauncher> rocketLaunchers = new ArrayList<>();
private final List<HandGrenade> handGrenades = new ArrayList<>();
private final List<LandMine> landMines = new ArrayList<>();
public Builder rocketLaunchers(List<RocketLauncher> rocketLaunchers) {
this.rocketLaunchers.addAll(rocketLaunchers);
return this;
}
public Builder handGrenades(List<HandGrenade> handGrenades) {
this.handGrenades.addAll(handGrenades);
return this;
}
public Builder landMines (List<LandMines> landMines ) {
this.landMines .addAll(landMines );
return this;
}
public Arsenal build() {
return new Arsenal(this);
}
}
}
You can now use this in the following way.
List<RocketLauncher> rocketLaunchers = //whatever
Arsenal arsenal = new Arsenal.Builder().rocketLaunchers(rocketLaunchers).build();
....
weaponCountMap.put(Weapon.HAND_GRENADE, arsenal.handGrenades);
//.. and so on
All fields of the arsenal are non-null, and can't be modified. If you define the builder in an external class (i.e. not a static class within Arsenal) your Arsenal class will be very small - just fields and the constructor, plus logic methods.
Please have a look at other posts like this one...Java Conventions: use getters/setters WITHIN the class? to obtain an idea on when you could use getters instead of direct access.
Its kind of a design question depending upon what you would like to encapsulate within your arsenal class and what you would like to expose to the outside world for viewing your arsenal.
Its like the UN trying to inspect your arsenal and you tell them hey I wont tell you what weapons I am dealing with in my arsenal but I can give you a report and that is the report you externalize to the outside world. Now it depends on you what report you want to give out and which weapons will land in that map of yours.
Now looking at your second technique, are you planning to shift the map creation logic into your Arsenal class.
Another design question to answer .... is this logic just to obtain reports then my suggestion is to keep it out of the arsenal class and keep it light.
Otherwise you might end up putting in all kind of report logics into the arsenal class and it will get heavier and might explode.
See https://projectlombok.org/ or https://github.com/google/auto/tree/master/value.
Add separate field for each weapon, Lombok or AutoValue will create getters/setters/hashcode/equals/toString methods for you.
I have following classes
class A {
private Long id
private List<B> listB;
private C c;
...
}
class B {
private Long id
private A a;
private List<D> listD;
...
}
class C {
private Long id
private A a;
...
}
class D {
private Long id
private B b;
...
}
I need a copy of A, include all of it's properties except all id column.
I have 2 solutions:
1. Clone each object and set all of the ids null;
2. Make a constructor like this:
public A (A a){
//copy all properties except id
this.xxx = a.xxx;
...
}
But i need write so much code for this function, any one has some better method to implement this function?
Thanks a lot.
When you are saying Deep cloning of the object particularly the one of type Class A where you have an instance variable of a container type, you have below two widely known ways:
1) You Serialize and Deserialize the object.
2) You traverse through each method and call clone explicitely.
For first implementation, you may mark the id fields as transient and that should solve your purpose.
For second approach, you may override the clone method in each class where you set the id field as 0/-1) and call super.clone()
You can use Mapstruct , it's a powerful mapping library where you can configure all the fields exclusions for your specific class or nested class, without having to write all the getters/setters manually.
I personally use it for deep cloning jpa entities excluding ids or auditable fields.
Ex:
#Mapping(target="id",ignore=true")
EntityA cloneEntityAWithoutId(EntityA origin);
Mapstruct will generate for you the implementations using getters and setters of the EntityA, excluding the id field.
Obviously is a lot configurable, see the documentation I shared above.
While creating a Web service I decided to exchange Business Object (BO) between client and web service.
If in the future I get a request to expand my model and put some new attributes (field) in my BO and send it to the client, what would be the best approach?
So basically, each BO may have 0..n meta-fields.
Each meta-field is Key,Value like, where keys can be anything from simple data types to other BOs.
Here is a little Java code for modelling BOs, I just need confirmation that I'm on the right track.
class AbstractBO{
//optional list of meta fields for future extension
List<MetaField> metaFieldList;
//setters. getters
}
----
class MetaField {
private Object key;
private Object value;
// setters
// getters
}
----
class MyBO extends AbstractBO {
//BO specific fields
private String name;
...
}
---
TODAY
class Person extends AbstractBO {
private String name;
private int age;
//extend metaFieldList = null;
}
----
TOMORROW
class Person extends AbstractBO {
private String name;
private int age;
//list with new metafield
}
How to model Person for Tomorrow purposes?
If, as your follow-up comment implies, you actually want to send the direct object code (presumably by implementing Serializable) instead of using a XML or JSON (which is what you'd typically do when implementing a web service), then I don't know how you'd actually be able to achieve what you want.
When Java tries to recreate your object by deserializing it, it will have to match the input data against what it believes the class to be. For best practice purposes, you should be implementing serialVersionUID and changing it each time you modify your class so that when you add variables, the person on the other end won't be able to erroneously reconstruct the class that you send them if they have an old version of the code.