Classes and Properties

I have a problem and solution, but I'm not very happy with this:

My problem:

I have several classes and several "properties". These properties are not described by a method or a boolean. They are defined by those classes that have a property (common features).
Now the groups of classes with the same properties should be formed. These groups can be interpreted as sets. The properties of subgroups (subsets) are not necessarily related to the properties of the parent group (superset).
In addition, the compiler can check these groups for correctness by type.

Previous solution:

An (possibly empty) interface is created for each group. All classes with a common property implement this interface. Group and interface for all classes with this property. If you now pass the parameter to a method that should only accept classes with a specific property, then the parameter type is the appropriate interface.

Description of the example:

All classes implement the interface using the m1 method.
An interface is created for each property, which is implemented by all classes that correspond to the corresponding property. Properties can be, for example, side effects that occur when you start this method.
Thus, an interface is a collection of classes with the corresponding property. It is a property, so to speak.
In addition, there is another method m2, which receives as an parameter the object of a certain group of properties. In m2, m1 is called from the given object. Thus, we are aware of the side effects that occur when you start m1 or the property that is running. It is not possible to pass an m2 object without the corresponding property / side effect, because the compiler checks the type is correct.

Example Code:

(Side effects are presented through exit)

public class Example { public static void m2(Property_12 p_12) { p_12.m1(); } public static void main() { Class_1 c_1 = new Class_1(); Class_2 c_2 = new Class_2(); Class_3 c_3 = new Class_3(); m2(c_1); m2(c_2); // m2(c_3); // Is not passed by the compiler (wrong type) } } interface Combinable { public void m1(); } interface Property_12 extends Combinable {} interface Property_13 extends Combinable {} interface Property_23 extends Combinable {} interface Property_123 extends Combinable {} class Class_1 implements Property_12, Property_13, Property_123 { @Override public void m1() { System.out.println("Property (1,2)"); System.out.println("Property (1,3)"); System.out.println("Property (1,2,3)"); } } class Class_2 implements Combinable, Property_12, Property_23, Property_123 { @Override public void m1() { System.out.println("Property (1,2)"); System.out.println("Property (2,3)"); System.out.println("Property (1,2,3)"); } } class Class_3 implements Combinable, Property_13, Property_23, Property_123 { @Override public void m1() { System.out.println("Property (1,3)"); System.out.println("Property (2,3)"); System.out.println("Property (1,2,3)"); } } 

Why am I not satisfied with this decision?

My concern is not a specific case, but a general problem. The number of created interfaces is growing rapidly in the air:

  • possible combinations = set power of a set of all classes
  • | P (C) | = 2 ^ | C |

If the interfaces / groups are configured, as in this case, according to a specific system, there should be a way to solve everything more elegant than writing an interface for each group. Efforts to Create 2 ^ | C | the interfaces are already huge, and if possible you can reduce it at least.
If now you want to summarize several properties, you are again faced with the same problem. Thus, you will need to create any combination of interfaces for the interface:

  • | P (P (C)) | = 2 ^ 2 ^ | C |

If you process a huge number of letters, you can transfer objects with several properties.

I hope that my wording is clear enough, and there will be one or the other interesting proposal.

Thanks for your efforts!


There is always 2 ^ | C | interfaces. Perhaps I can use a code generator to create these interfaces. What do you think of this idea?


C = The set of all classes that should be grouped.


It is important that each class has something in common with one, two, ... and | C | -1 others, so that every possible "combination of classes" (= grouping) exists. In addition, no set can appear twice. It follows that the set of all groups is a set of degrees. My properties are groupings.


You can ignore singleton sets (and empty sets), since this is the class itself. So the formula is actually:

 |P(C) \ ({ {x} : x in C } add "empty set")| = |P(C)| - |C| - 1 = 2^|C| - |C| - 1 

Example:
| C | = 2 => | P (C) | - | C | - 1 = 2 ^ | C | - | C | - 1 = 2 ^ 2 - 2 - 1 = 4 - 2 - 1 = 1 (= groupings / interfaces)

 Class_1 --| |--> P_12 Class_2 --| 

Example:
| C | = 3 => | P (C) | - | C | - 1 = 2 ^ | C | - | C | - 1 = 2 ^ 3 - 3 - 1 = 8 - 3 - 1 = 4 (= groupings / interfaces)

  |-- Class_1 --| | |-- P_12 --| | Class_2 --| |-- P_123 P_13 --| |______ | | | |-- P_23 --| | |-- Class_3 --| | |____________________________| 

Specific example:

  |-- PolarBear --| | |--> White --| | Swan -------| |--> Animal Mammal <--| |_________ | | | |--> Fly ----| | |-- Bat --------| | |___________________________________| 

Code:

 public class AnimalsWithProperties { // It can be passed only white mammal. public static void whiteAnimal(White w) { w.shout(); } // All animal can be passed public static void animalShout(Animal a) { a.shout(); } public static void main(String[] args) { PolarBear e = new PolarBear(); Swan s = new Swan(); Bat f = new Bat(); whiteAnimal(e); whiteAnimal(s); // whiteAnimal(f); // Error animalShout(e); animalShout(s); animalShout(f); } } interface HasAnimalProperty { public void shout(); } interface White extends Animal {} interface Fly extends Animal {} interface Mammal extends Animal {} interface Animal extends HasAnimalProperty {} class PolarBear implements White, Mammal { @Override public void shout() { System.out.println("PolarBear: I am a white Mammal."); } } class Swan implements White, Fly { @Override public void shout() { System.out.println("Swan: I am white and can fly."); } } class Bat implements Fly, Mammal { @Override public void shout() { System.out.println("Bat: I am a flying mammal."); } } 
+4
source share
3 answers

If you want to treat these properties as interfaces, I highly recommend finding a way to automatically create classes and / or interfaces.

I would personally take a look at Clojure's methods for generating interfaces, and that literally allows you to pass a list of strings for creating interfaces. Then you can easily pack the resulting set of classes into a jar and use it for the rest of your project, which can be written in Java (or Clojure in this way). Automatically creating a power set of possible classes will also be relatively simple.

Another possibility that fits the above is to use a bytecode generator to create interfaces and classes, although I think it would be easier to use the above.

+1
source

I would not consider properties as general classes in myself. This is like adding a lot of complexity to an uncertain win. If you want to pass a certain number of properties, you can use a simple method.

 object.method(p1,p2,p3,p4,p5); 

If you go through many arguments, you can wrap them in logical parameter groups. However, you decide what a logical group is.

+2
source

Java really is not suitable for what you need if you want the compiler to validate.

You may be able to achieve a less cumbersome solution with annotations and some reflexive checks that can be automated, albeit with great pain, but this would not be consistent with your goal - to make the compiler a check.

A possible alternative to automating reflective testing might be a smart solution with method handles, but I cannot offer any real advice on how to do this work. Perhaps if you annotated an object with a property and then annotated the function / method as accepting things with this property, you could associate the sending system with a method descriptor structure that will be checked at runtime. A different pain than reflection is probably less, but then again, it is still checking the execution time.

+2
source

Source: https://habr.com/ru/post/1383066/


All Articles