0

I have been developing in Java specifically over 5 years now.

Now always when I start writing a new class or code, I start with defining the properties of my class. So I will need to hit eclipse generate getter and setter every time to my dissapoint. And that is cleaner code and much more understandable in the end.

But I enjoy thinking abstract and using of OOP and generics. So there is either an specific reason people need to use Java primitives or we can just create a class like this in Java to always have an getter and setter and still be within the normal use of Java class members :

public class Property<Type> implements Getter<Type>,Setter<Type>{

protected Type value;

public Property() {

}


@Override
public <T extends Type> void set(T value) {
    this.value = value;
}

@Override
public Type get() {
    return value;
}


public String toString() {
    return value.toString();
}

}

You can still use modifiers to limit the access to the variables you define. You will still use the same variable declaration as in:

     Class test{

     private Property<Number> priv_floatProperty = new Property<Float>();
     protected Property<Number> prot_floatProperty = new Property<Float>();
     public Property<Number> publ_floatProperty = new Property<Float>();

     }

Just wanted to ask this question to see what other people think about this code and writing your classes in this way. I really hope I can get some feedback about this code and the theory of class design in Java,

  • 1
    Unnecessary complicated. And your cast in `get` method is not safe. – tsolakp Oct 26 '18 at 22:41
  • 4
    Please take a look at [Lombok](https://projectlombok.org/) which partially addresses the boilerplate code of getters/setters. – Alex Shesterov Oct 26 '18 at 22:43
  • and if you want to set some property in the class that uses that, you'll need to write a setter to call the setter of that Property.... – user85421 Oct 26 '18 at 22:49
  • Well it's safe enough not to cast to String for instance in above example. It will give that error on compiling "Type missmatch". So it will only cast the get method back to any child of Number. I mean isnt that type safe? And complicated? I like this design much more then have to write getters and setters each time in my code. – Pouria Jafari Oct 26 '18 at 22:49
  • @CarlosHeuberger, sorry but you can use the . notation if its accesable right? like anyclass.myproperty.set() – Pouria Jafari Oct 26 '18 at 22:53
  • @Pouria Jafari What you think will happen when you do this: `Integer t = priv_floatProperty.get();` – tsolakp Oct 26 '18 at 22:58
  • 1
    @Pouria Jafari. Does not matter. In either case it is not safe. Any parametrized method that cant check for client's expected return type is not safe. – tsolakp Oct 26 '18 at 23:34
  • I agree it introduces too much complexity. If this was a common pattern, you'd actually be seeing it in common repositories – OneCricketeer Oct 26 '18 at 23:44
  • @tsolakp I edited the class. It will return the declared type but you can set it otherwise to any extended class of that type. Still not good? Let me clear my self up a bit, what if you had to write a a class with more then 1000 kind of properties. Which solution you would choose? – Pouria Jafari Oct 26 '18 at 23:45
  • Doing it the way you're proposing, what do you do when you have a List field, and you want to make sure the getter will always return a copy of the list, and an add() method that ensures consumers can't have access to the underlying list? – cleberz Oct 26 '18 at 23:50
  • @Pouria Jafari. The get method looks ok. – tsolakp Oct 27 '18 at 00:01
  • @cleberz You can override the get method in an anonymous class function when you need to. Or create an add function for the specific variable. You can use it then when accessing the variable right? – Pouria Jafari Oct 27 '18 at 00:13
  • The bigger issue here is that you shouldn't be exposing accessors, especially setters, for all object properties. Tell, don't ask: if you only treat your classes as bundles of properties then you're doing structured programming, not object-oriented programming. – Daniel Pryden Oct 27 '18 at 00:22
  • sure you can use ``anyclass.myproperty.set`, but why not use `anyclass.myproperty.value = ...` - `myproperty is not adding anything, Using an object just/only to hold another object is a bit strange to me, Why not have another object to hold the object that is holding the object? It's ok, IMO, if it has some additional functionality (or *semantic* reason) but just to have it? – user85421 Oct 27 '18 at 08:22
  • How about immutability? Do you have some sort of Property class that prevents someone from calling set()? – cleberz Oct 28 '18 at 01:22
  • @CarlosHeuberger Thank you for your opinion. One of the advantages in functionality it has is the setter and getter are not part of the containing class anymore. You access the property first and then use set like anyclass.property.set(). Read my next answer to cleberz for the advantages. – Pouria Jafari Oct 28 '18 at 13:16
  • @cleberz In fact my idea was to let the getter and setter interface be implemented by a child of the Property class. The complete apprauch would be ofcourse to have a for instance an astract property class and have subclasses like immutuableproperty, or a NotNullProperty.. I will take a look at the Optional implementation in Java to see how they done that. And I am also trying to create an example for instance with a property "time" inside a class for instance to show the advantages. Will post later today the example code. – Pouria Jafari Oct 28 '18 at 13:20

1 Answers1

1

I think that you should use generics only if necessary.

First, for readability.

Second, you can fastly hit the Java Type Erasure problem (see). So you could encounter lot of problem when comparing classes (and the use of appropriate .equals/.hashcode methods). I have seen some difficult cases where the only solution was to use unreadable, complicated and performance-cost reflections...

As suggested, you can use Lombok to make an abstraction of getters/setters.

cactuschibre
  • 1,908
  • 2
  • 18
  • 36