I solve the problem of finding a leader ( leader election ) This is a purely algorithmic problem, which has 2 forms: a unidirectional ring and a bidirectional one. To represent the data, I created my own class for a list, twisted into a ring. That is, I have two algorithms, one for each form of the task.

public abstract class MyAbstractRoundList { protected int size; protected Agent[] arr = new Agent[1]; protected int index = 0; public boolean isEmpty() { return size == 0; } public int size() { return size; } public void add(Agent agent) { if (size >= arr.length) { Agent[] temp = arr; arr = new Agent[temp.length * 2]; System.arraycopy(temp, 0, arr, 0, temp.length); } arr[size++] = agent; } // и дальше еще много методов 

Next, I create the heirs of this class for unidirectional mode and for bidirectional. The implementations in them are certainly different. Next, I have a class:

 public class LeaderElection { public static void solve(MyAbstractList list, int i) { if (i == 0) { list.initiateStartState(); } else { list.setMessages(); } } 

}

I have a solution for unidirectional mode in it. And there is a similar class with a solution for bidirectional, but the implementations of course also differ. What not to register in the client code

  if(isOneDirectMode()){ LeaderElection.solve(); { if(isBiDirectMode()){ BiLeaderElection.solve(); } 

I could also create an abstract class for the solution and its heirs and use polymorphism (as I do for lists). But here comes the problem: I have parallel inheritance hierarchies. If a new mode appears, I will have to add a new subclass of MyAbstractRoundList and a new subclass of the solution. How can you get rid of it? I see only one way: It would be possible to make the abstract (solve) method in MyAbstractRoundList and implement it in the subclasses of each mode as required for a particular mode. But this is bad, because then my subclasses of MyAbstractRoundList will not only store data, but also solve the problem. That is, to perform 2 functions.

  • one
    And what is bad parallel hierarchy? - VladD
  • @VladD, your question stumped me) I don’t even know, but I always thought it was bad. Maybe because they can not agree? - Alexander Elizarov
  • See it. It is clear that the extra functionality does not need to be included in the main hierarchy, so the code "side" is necessary. The problem is essentially in dispatching: when you call a virtual method, having a reference to the base class, you call the correct method of the derived class. And when you instead have a parallel hierarchy, the language cannot dispatch a call by type from the main hierarchy. - VladD
  • Therefore, it is necessary to manually assign the type from the additional hierarchy to the main type. (Yes, this is a painful moment, it cannot be automated.) But this is in fact a good compromise to not pack all the functionality together in the basic hierarchy. [Well, in your particular case, the parallel hierarchy may not be necessary, but this is not so important.] - VladD

1 answer 1

They are not parallel. Changes in one hierarchy do not entail changes in another hierarchy.

If a new mode appears, I will have to add a new subclass of MyAbstractRoundList and a new subclass of the solution. How can you get rid of it? I see only one way: It would be possible to make the abstract (solve) method in MyAbstractRoundList and implement it in the subclasses of each mode as required for a particular mode.

Problem solving is behavior . Behavior is better described by interfaces.

 public interface Solver { void solve(MyAbstractList list, int i); } ... public class LeaderElection implements Solver { ... public class BiLeaderElection implements Solver { ... public class MultiTreadingLeaderElection implements Solver { 

You have a separate inheritance hierarchy of classes responsible for storing data, and a separate hierarchy of classes responsible for decisions. This is normal. If a new storage type appears (new type of list), you will add a new class MyAbstractRoundList . This has nothing to do with decisions, the new class can also be used by existing solutions. If you need to add a new solution, you will add a new class that implements the Solver interface, and this does not have to affect the class hierarchy for storage.

With this approach, the solver.solve(abstractList, i); code solver.solve(abstractList, i); will always work for you solver.solve(abstractList, i); , if you put an object of any class that implements the Solver interface into the Solver variable, and any object of the MyAbstractRoundList , and the abstractList variable, and most importantly, this code will not have to be changed when adding new classes, as it should be from the OOP point of view.


UPD. There is data, there is behavior. Within the class, fields describe data, methods describe behavior. For example, I lead a team of robots. Some of them can be built , others can be carried , others can be destroyed , and others can be watered . A robot builder, for example, can bring construction materials to itself, but only in small quantities, so it can be both built and worn. A carrier robot is only worn. And if suddenly the task is to urgently unload the wagon of building materials, then I need to collect all the robots who can wear. And I do not care what kind of robots. Though a robot sprinkler. If you can wear - let him go wear. I will simply choose robots with the behavior I need , and I will be sure that they will be able to do what I need.

 public interface Carrier { void carry(); //нести } public interface Builder { void build(); //построить } public interface Destroer { void destroy(); //сломать } public class RobotBuilder extends Robot implements Builder, Carrier { public void carry() { } public void build() { } } public class RobotDestroer extends Robot implements Destroer { public void destroy() { } } public class RobotCarrier extends Robot implements Carrier { public void carry() { } } 
  • and what is the behavior, please tell me? Is this some kind of pattern? - Alexander Elizarov
  • one
    Added an explanation. I hope it is clear. - Pavel Krizhanovskiy