0

Consider we have three classes which want to collaborate, then, where is the behaviour?

I guess it can only be in one of the three classes or in a fourth one acting than as a procuedural connector-class, which separates the behaviour from the three classes and to its own class.

But also if we don't have this connector class then one of the three ecapsulate the behaviour of the other classes.

Let us have a lawsuit with a judge, an accused person, and an attorney.

Then we ask the judge to make a decision, or we ask the lawsuit itself. It then has to ask the other ones for details to make a decision and maybe to change the state of all of them. For example, the attorney gets now the state that he isn't free anymore.

The question here is inspired from here: Which object should have the method?

There are two solutions, where to put the behaviour.

One solution from Greg Burghardt + Martin Maat, they point to a procedural solution. They put the behaviour to a Controller-Class. Why procedural? Because the behaviour is separated into the Controller-Class from the Buisnessobjects (User and Chatroom)

And there is a theoretical object orientend solution from Robert Bräutigam, putting the behaviour into one business object, into that one which doesn't pull out data from the other collaborating buisness objects.

And now I'm interessted, how that should work, the solution by Robert Bräutigam. The Chatroom User example itself needs - I guess - informations from each other. My example with the lawsuit also from all others, they have to pull out data every time.

In the comment section https://softwareengineering.stackexchange.com/a/418453/347781 :

But what you would say if both sides pull out the data?, ok i put the behaviour to the Chatroom, but the Chatroom pulls then out the data from the user, because it needs to fullfill its algorithm data from both,....... maybe then we have a third party, fourth and so on, The Chatroom would pull out data from all of the others. What kind of benefit i have to put then the behaviour to the Chatroom. On which metric i can decide to put it to the Chatroom, because you said placing the bevahiour to that location, which dont pull out data, but if each one of them pull out data?^^ – Robin Kreuzer

@RobinKreuzer You have to come up with a design in which no objects pull data out of other objects (some rare exceptions apply). That is what object-orientation is at its core. Objects are there to contribute behavior. It is the key factor that makes oo more maintainable than procedural programming. – Robert Bräutigam

I came from the procedural/functional programming world, so i prefer also the Controller solution. But I don't think - as i wrote -, that this is object oriented in the core. I will post a specific question to this in the future also explaining in that, why Controller/Service based programming is pure procedural.

But here I want to know, how that would work, don't pulling data out from each others. Im looking for an example, how that should work, if the behaviour/algorithm needs data from both, how i should do this with my lawsuit, the chat-user example, and how that should work in general? And what kind of rare exceptions Robert Bräutigam means, if softwareprojects uses their core-logic in more 90% in their code in Controllers/Services (this number is not proofen, only a opinion based feeling)

I also want to know, if there is a rare exception, what to do then? Where is the behaviour then?

It seems for me, that the rare exceptions are the main-case we have to deal with daily, and there is no other way than coming up with the procedural way.

I can't see tell one and tell the others simultaneously. It seems to be a intrinsic paradox.

Edit (because there was wishes for a code example):

a few less behaviour data classes (they are not complete):

class User {}

class Chatroom{}

class Rights{}

class ClockService{}

class Command{}

one pre-word to the getRights().isFunnyLevel().getFunnyLevel() it' some kind of optional there, so don't think too much about it^^

class CommandService
{

//other services

    /**
     * This method is called by the System/Procedures/Controller sitting in the ConnectionPackage.
     */
    public void doAction(User user, String command)
    {
        final Command commandParsed = this.parseCommand(command);

        switch (commandParsed.getType())
        {
            case "messageToChannel":

                Chatroom chatroom = this.chatRoomService.getRoom(commandParsed.getParameter1());

                if (user.getRights().isAdmin())
                {
                    chatroom.write(user, commandParsed.getParameter2());
                    return;
                }

                if (!chatroom.isEnteredUser(user)) throw new CommandExecption("User not loggeg in this channel", 5007);


                if (chatroom.isMuted(user) || user.isMutedForChatroom(chatroom)) throw new CommandExecption("User is muted in that chatRoom", 5007);


                //i dont want to let Chatroom act as a big facade
                if (chatroom.getModeObject().getSomeDeeperGraphObject().getFoo().getBar() == "XY" && this.clockService().isBetween9and10oClock() && user.getRights().isFunnyUser().getFunnyLevel() == 7 && user.isConnectedWithWebsocket() &&
                    user.sendMessagesInTheLastHour > 30 && chatroom.recievedTotalMessageInTheLastTwoHours < 70 && chatroom.getUserStat(user).recievedMessageInTheLastTwoHours > 20 /* and so on*/)
                {
                    if (chatroom.owner == user)
                    {
                        chatroom.writeKursive(user, commandParsed.getParameter2());
                        user.incrementMessageCounterToOwnChannel(commandParsed.getParameter2().length());
                        if (!(user.isUserWithLogorrhoe && this.clockService().after9_30()))
                        {
                            user.incrementMessageCounterTotal(commandParsed.getParameter2().length());
                        }

                    }
                    else if (/* some more/other checks*/)
                    {
                        chatroom.writeBold(user, commandParsed.getParameter2());
                        user.incrementMessageCounterTotal(commandParsed.getParameter2().length());
                        this.mailService.sendMailToAdmin("YIPIE");
                    }
                    else
                    {
                        chatroom.writeColourful(user, commandParsed.getParameter2());
                        //here we dont want to increment any messageCounter

                        if (this.getRights().isFunnyUser().getFunnyLevel() < 10 && user.getXYAttribute = "bar" && channel.getDetails().getHistory().getCreateTime < user.getCreateTime + clockService.getMonthinTime())
                        {
                            this.getRights().isFunnyUser().incrementFunnyLevelWithStep(2);
                            this.clockService.adjustTimeByDecrement2Hours();
                            if (/*..*/)
                            {
                                chatroom.setNiceLevel(5);
                            }
                            else
                            {
                                chatroom.setNiceLevel(3 + user.getNiceCounter());
                                user.niceCounterDecrement(2);
                            }

                            this.user.muteUserForAllChannelBeginsWith(channel.getName().getFirstTwoLetter());
                        }

                    }

                }


                if (/* */)
                {
                    //...
                }


                break;
            //...

        }

    }


    private Command parseCommand(String Command)
    {
        //...
    }
}

A few notes to this example:

In this example i use a classic procedural style. the service/procedural-method is telled doing its job. One refactoring step would be, to move the code direct into the ChatRoom class; Then this class would be telled, the others would still be asked. Of course i could there also divide and conquer a little bit, don't having all the code in one big method, but in more methods/procedures. But anyway, i'm more interested, how i can get out of that example a perfect object orientend code and not presenting by me a perfect procedural code.

One extra note:

Maybe i want to reuse that big code in the first if(...) in a parameterized way on different locations in my application. Maybe also in case ban or join_room to get there a special treating, if the if(...) is true. It's easy to make out of that a if(...), which itself ask a lot of others, a own procedure/function. So the code-reusability is great here.

But now im interested, how to get a code out of it telling one and telling the others and why it is good to program like that dispensing on code-reusability. Or, i am wrong here in the last point?

Doc Brown wrotes in the comment section in another question (No trivial god-class refactoring) by me the following

[...] (good candidates are those who work with user attributes exclusively, and need almost nothing else) [...]

he means there the methdods which should only work on the member variables of the user (or in other words: Of the object on which we take our focus) itself.

I think code belonging and working only on the object itself is only the 100%-90% = 10% i mentioned earlier in the question here in some other context. And the other 90% (Controler/Service-Code) is the code which needs to interact with different objects the same time.

But as i understood Robert Bräutigam correctly, it should be exactly the other way around.

But i can't see how i should refactor my code to match this criteria.

So i'm interested how you would do the magic (telling one and telling the others),

why you also think so much people prefer the procedural (buisiness-relevant stateless Controller/Service) approach, why it is better to program in a object oriented way, where the behavior and data are encapsulated also with the limitation don't fullfilling the SOlID in particular the S (Single Responsibility)

The thought with the limitation is not by me, but from Robert Bräutigam; and i have to agree with him. Having only one class (one good-class) in your project means no SOlID, but means also no asking the others, because i only tell with myself, but is that the answer to my question?

One last and side note:

If you take a look into my example, you will find different violations on LoD (Law of Demeter), i asked into deep (god-facades could be there the solution?), and i also change the state of that object with a part-information, i get out of that object, because i mixed it with some other state. (see in my example near the end the thing with the niceCounter)

Edit 2 (to focus more/again the main problem)

Let us concentrate more on the complex if and it's content in my example than the things around it.

i try it to make it more clear with the the following abstract/pseudo-code example:

if(
something from user &&
something from ChatRoom &&
something from something deep in the user, maybe the color of the users fingernail? &&
something merged from user and Chatroom (the niceLevels for example) &&
something from clock &&
something ....
)

then

{
change some state in the user
change some state in the ChatRoom
change some state in the niceLevels of user and ChatRoom
change maybe the clock?
change something in a third-party-object, which was not in the if-checks (maybe sending a notification/email or something else)
change some state in ....
}

let us take a look on the first part on the if:

There is a complex if-question/code which i don't think is mapable to if(constraints of object1) then call a method in object2 (what Robert Bräutigam shows in the last edit) which itself do there some checks, because we have there 1) more than two objects and 2) actions in the then-clause after all constraints are valid. Also we have here in the state some merged-state.

To the then-clause:

it's a transactional unit, all or nothing, if the if-clause is true.

Also let us vary the if and then clause a little bit, like i did in my first edit-code-example, so it is gonna be much more complex. We can have some more if-then-else, all with asking different domain-objects and all with different transactional then-clauses

Conclusion:

I can't see how you would map this to collaborating objects, which not ask each other (but only do their own stuff)? - But this is my question, how you would do this magic, which i can't see. How you would write such code, which not ask the others with that examples i given here

And why is writing these kind of code (if it exists a way to code like that) better than the procedural one, i present here?

Edit 3 (to transform the eample in edit2 to a lesser abstract one)

Appendix:

if(
user.getMember1() == 2 &&
ChatRoom.getMember1 == 79 &&
user.getMember2().getMember5().getFingernail() == 4 &&
user.getMember7() + ChatRoom.getMember20() ==70 &&
clock.getMember1() == 12
)

then

{
user.setMember1(50);
user.setMember33(40);
chatRoom.setMember90(10);
clock.setMember14(77);
user.getMember5().getMember108().getMember22().setMessageFilter(7);
bathroom.setMember20(55);
}
11
  • 3
    The only way this is answerable is if we work through a code example. Commented Mar 18, 2021 at 0:46
  • ok i try to create tomorrow a code example and add it to my question (now its a little bit late here in germany^^), but for short i can give that example. let us take the in my post linked chat-user-example. The user want to write a message into a chatchannel or want to join it. There must be different constraint fullfilled to allow this action and more. The channel capacity must not be full (->ask the channel). The user needs the correct permissons (ask the user) and maybe the channel is only joinable in the time between 9 and 10 o clock (ask the clock^^), and so on. Commented Mar 18, 2021 at 0:59
  • After joining the channel, the state is adjusted also in different classes Commented Mar 18, 2021 at 0:59
  • i hope the example is good, let me now if i should change something on it or the additional notes, and sry that i needed some more time that only that announced one-day Commented Mar 22, 2021 at 0:06
  • So, based on your code example, I think you're seriously overthinking this. Before getting into the finer details of architecture, like you're doing now, I suggest you focus on three simpler principles. They're not laws, mandates or edicts; they're simply guidelines. But these guidelines, if followed, will get you 90% there anyway. Here they are: Commented Mar 22, 2021 at 0:22

3 Answers 3

2

Sometimes porting procedural code into oo is as easy as renaming things. For example ClockService. You just rename it to Clock and it works. It is a thing, it is business-relevant, etc. I would also rename the method isBetween9And10OClock() for the same reasons. You could assign a business-relevant name, like isHappyHour(), or isAdminOnlyHour(). Something that is relevant to some use-case.

A lot of times you have to find a proper place for things. For example here:

Command command = this.parseCommand(serializedCommand)

Should become:

Command command = Commands.parse(serializedCommand)

So instead of someone else deserializing commands, let the commands know how to deserialize themselves.

The whole CommandService.doAction(...) could actually just go into Command. So for example Command.executeWith(User user). You also get rid of the switch-case this way, and instead use polymorphism.

All in all, I think it could start with this code somewhere:

Commands.parseCommand(input).executeWith(user);

Then there would be a MessageCommand implementation. I would perhaps find the proper chat room as part of the deserialization process, instead of looking it up during the execution. So the command would look like this:

public class MessageReference(ChatRoom room, String message) {
   @Override
   public executeWith(User user) {
      user.sendMessage(room, message);
   }
}

Note the command basically just delegates to a "model method".

The User could be similarly polymorphic, in which case the AdminUser would do this:

public class AdminUser {
   @Override
   public void sendMessage(ChatRoom room, String message) {
      room.write(this, message);
   }
}

And the "normal" user would continue with the rest. As you see at each turn we're just telling things to do their thing, not getting data out, and we could get rid of a lot of complexity.

You can continue this game until each thing only does a handful of functions and only function for which they have the necessary data themselves. I hope the couple of examples here can help you start.

Update: So let's continue a couple of steps, as you asked. I don't know your exact case, so I will assume some things that might not fit. So the big "if" statement seems to revolve around these things as far as I can see:

  1. User stats
  2. Chatroom stats
  3. Some chatroom status
  4. User rights & time
  5. User connection type
  6. ...possibly more...

The obvious place to start is to split this "if". Handle the parts that the User object might know in the User, and move parts into ChatRoom which concern the ChatRoom.

There's a little more to it though. You'll have to come up with a business case. It's not just random conditions, there must be a "business" motivated reason for them. So name those.

Let's see how that would translate to the User (as I've said I'll assume things here):

public class User {
   @Override
   public void sendMessage(ChatRoom room, String message) {
      if (!isUserSpamming() && !isUserMuted() && isConnected()) {
         room.write(this, message);
      } else {
         ...
      }
   }
}

Continue with the ChatRoom related checks there. Does this help?

12
  • Of course i would never write such code as written in my example, things how i can replace switch cases with polymorph program code is known by me^^. But now to the main problem, is not bringing some polymorphism into all of it, but how to code the complex thing which i descriped in my if(...){...}. The thing with the admin user was unfortunately in my proced. code also trivial (there was here also no asking some others^^). But let us assume also a Admin isnt allowed to write into each channel! Maybe you can show how coding the part beginning with if (chatroom.getModeObject().getSomeDe... Commented Mar 22, 2021 at 17:42
  • There is some more question. you have the method sendMessage in AdminUser (and in the interface User), now my project is growing up, then i get into the problem getting a User with 100-1000 methods, how you would avoid this? -> AdminUserForChat (UserForChat) as composition? Maybe you can make this more explicit in your answer..... One more problem i see here, if the adminUser writes in your example the decision is maked in the AdminUser, decisions related an other user Role would be more maked in other classes, but starting with such design means having also a sendMessage in the normalUserRole Commented Mar 22, 2021 at 17:48
  • a proecdural style would detach that functionality from each buisness-object and let it stands alone (best re-usability?) The point to the let find the command the correct ChatRoom. Maybe i want to use this command-System also for other cases; so its also growing up with things which is not command specific (single-responsibility), but why you would prefer such solution, and are there still solutions beeing object orientend and get die possibility of code-re-usability? Commented Mar 22, 2021 at 17:54
  • 2
    @RobinKreuzer Again, there is no generic/magic solution. If you think something would not work, you'll have to show an example why. Commented Mar 25, 2021 at 7:34
  • 1
    @RobinKreuzer I think you're missing the point. You are still expecting me to give you some generic / mechanic transformation that will create OO from thin air. If you give me gibberish code, I'll just won't know what to do with it. OO design relies heavily on (business-related) reason / purpose. If I can't imagine what that is, I can't come up with a design for it. Commented Mar 25, 2021 at 16:55
2

Code is abstraction, and abstraction is, well, an abstract concept. It's all about how you reason about the problem domain and how you break down the problem into its constituent parts and how these parts interact with one another.

Functional and object-oriented approaches are very different, and both comes with their own benefits and drawbacks, but they are both valid approaches.

There is no universal answer. There are cases where a particular approach yields a particular benefit you're interested in, and there are cases where several approaches are equally viable.


The first part of this answer focuses on the code you posted, rather than the specific question you asked.


SRP and OOP

class CommandService
{
    public void doAction(User user, String command)
    {
         // WAAAAAAAY too much code
    }
}

Your code desperately needs to be broken down into separate responsibilities. Looking at the code, it puts your question in a new light. The question is on a fairly advanced topic, but based on your code, the actual problems you're faced with are on an elementary OOP/SOLID level.

You're not looking to build an orchestrator, you're building a god class and simply refer to it as if it's an orchestrator.

In your defense, you're working from a CLI-based interface, which does mean that you need a central hub which connects the input command to a large variety of command handlers and related business logic, and these hubs are often at risk of becoming too godly for their own good.

But you're really going to need to ensure that this hub does nothing more than routing your command to the correct command handler. Your hub should not start performing business logic checks or actions, because that is a massive SRP violation and will yield the type of god class you're already dealing with.

The amount of refactoring needed in your code sample is too large to address in a Q&A format here. But to help you get started, at a base level, separate your code into specific command handlers. I.e. for every switch case:

switch (commandParsed.getType())
{
    case "messageToChannel":
        // ...
    case "anotherCommand":
        // ...
    car "aThirdCommand":
        // ...
}

Consider making specific command handlers, so that each case is separated into its own problem domain.

public class MessageToChannelCommandHandler
{
    public void Handle(MessageToChannelCommand command)
    {
        // ...
    }
}

All necessary information should be included in that MessageToChannelCommand object, e.g. the current user, the current chatroom, ... Whether you pass the user/chatroom objects themselves or only an identifier is contextual, but usually it's easier to pass a reference because that means your hub didn't need to instantiate the actual user/chatroom, which helps lighten the load on your hub.

I also strongly suggest looking into the mediator pattern, and Mediatr specifically, if you want to learn a pattern that is highly effective for routing between different handlers, which seems to be what you want here.


The rest of this answer focuses on the question you asked, rather than the code you posted.


Encapsulation

But also if we don't have this connector class then one of the three ecapsulate the behaviour of the other classes.

You say that as if it's a bad thing. As with most things, context is key.

For example, you could argue that validation (e.g. PersonAgeValidator) is implicitly part of the actual business logic (e.g. NightClubEntranceService), and then there's nothing wrong with NightClubEntranceService encapsulating PersonAgeValidator.

Then we ask the judge to make a decision, or we ask the lawsuit itself. It then has to ask the other ones for details to make a decision and maybe to change the state of all of them. For example, the attorney gets now the state that he isn't free anymore.

I'm not sure if this was intentional or not, but this real world analogy is actually a clear cut case. The judge orchestrates the entire proceedings. They decide who speaks when, and when to move on to the next thing. They also arbitrate in cases of conflict or dissonance between the constituent components.

The judge quite literally swings the hammer here, and they are the orchestrator of the court's proceedings. For example, one side's lawyer is generally not allowed to address the other side directly, they have to talk to the judge who in turn talks to the other side if necessary.

Encapsulation purism

And there is a theoretical object orientend solution from Robert Bräutigam, putting the behaviour into one business object, into that one which doesn't pull out data from the other collaborating buisness objects.

I'll be open and honest here, I've discussed similar topics with Robert many times and it is clear that we disagree with one another on a fundamental level. I'm not saying that there is never any merit to his approach, but I find it a heavily skewed perspective.

Let's step away from coding and look at cars. I like supercars. They are loud and outspoken, elegantly engineered, squeezed for performance, always innovative, and they really accentuate the definition of what a car is. Supercars are the very essence of cars and the driving experience you get from them.

But there are also trucks. I'm not particularly interested in trucks, they're pretty much the least sexy vehicle imaginable. Trucks are comparatively dull, have simple engineering, are not fast, agile or corner particularly well.
But the truck isn't intended to be driven for the sake of the driving experience. The truck is all about the cargo it transports, and every decision on how to build the truck was favoring the efficient transportation of cargo, rather than making it a really nice and impressive driving experience.

Trucks also have to comply with standardization much more. While every new supercar can reinvent the (almost literal) wheel in every way and look radically different from another supercar, trucks should adhere to standard sizes so that they are able to carry standard size pallets and park in standard sized loading bays.

If you observe a loaded truck (as a matter of important parts), you'll notice that the truck itself is minimized in favor of the cargo it carries. The more cargo your truck can have, the better your truck is. But for supercars, it's all about the supercar. The supercar itself is the star of its own show.

It's very similar for software projects. There is elegance in pure OOP and behavior encapsulation. You can make things intricate and highly engineered and squeezed for performance to really highlight the pinnacle of software.
However, much like trucks, many software projects are more about the transportation of data than they are about intricate and innovative behavior. They transport large data loads, and therefore the software is not designed for elegance, but rather for efficiently transporting the data from A to B with the least amount of hurdles.

Pure OOP encapsulation that minimizes data fetching and maximizes functional interfaces is a massive obstacle in the face of efficient large data transport, much like how the average supercar's body is not easy to get in/out of. For every object you cross, you have to effectively repackage it over and over. And that's not efficient.

Much like how all different manners of trucks are able to move the same container with minimal effort in changing truck, data-driven applications favor having data objects which travel across the application from the database to the end user (or vice versa). It may not be the most elegant or performance-driven from an engineering perspective, but it significantly cuts down on development time for no real benefit when the main stakeholders are not developers and are only interested in the data that is being transported.

At the end of the day, the odds are that you are working in a data-driven application, as they make up the vast majority of software projects nowadays. And in these applications, it is the data that is the star of the show, not the underlying engineering. Starting from that perspective, it's significantly more reasonable to favor minimizing the obstacles you encounter during the transportation of your data from point A to point B, and rigorous encapsulation which puts the stress on minimal to no data fetching is simply the antithesis of efficient data traversal.

And now I'm interested, how that should work, the solution by Robert Bräutigam.

I've genuinely tried to see things from Robert's point of view, but it simply clashes with most if not all common development guidelines you find nowadays. Not that it can't be done, but that this purist approach comes with a very strict regimen of development that is simply not adhered to for reasons of practicality and real life considerations.

I guess this part of the answer is more of a frame challenge than an answer. While I think Robert's approach isn't impossible, I don't see it being particularly cost-effective or desirable in terms of effort versus actual benefit in data-driven applications specifically.

3
  • to the code section: this was still an example by me (in the notice there i wrote, that this is not the perfect style also not in data-driven/proecedural programming); i would of course split it into different responsibilities^^. Not that there is now a wrong impression of me. But i choosen my example that way, given @RobertBräutigam more focus on the main problem; that he didnt solved right now. You write RobertBräutigams approach isnt impossible: do you have an idea how you would/could express my examples in edit2/3 in that approach? Commented Mar 31, 2021 at 15:01
  • You wrote OOP/SOLID, i think SOLID cant be OOP but only procedural (procedrual with pseudo OOP, here i mean things like controller/services, which are related to the main business-case stateless), so we have there SOLID + procedural (managed by pseudo OO) VS OO (encapsulation of data and behaviour)...... What do you think about that? Anyway as you wrote the data-driven approach (SOLID + proecdural) is not elegant but works and is straightfoward; there i fully agree with you^^. And now i want to get to know the other side, the OOP (encapsulation data and behaviour) Commented Mar 31, 2021 at 15:07
  • and it seems for me that there is no solution and the other side OOP (encapsulation ....) exists only in the theoretic world, till @RobertBräutigam convince my that this isnt so^^ Anyway, nice picture with the car and the truck by you Flater..... Only (but also for the other things in your post) you earn more than only my +1 of your post here^^ Commented Mar 31, 2021 at 15:09
0

This question seems like a marginally more specific version of "how do I model real world complexity in an OO paradigm?" There are many books on this topic, including Domain Driven Design (DDD) by Eric Evans. In DDD, Evans explains how to think about the dilemmas you perceive and ways to resolve them with good examples.

3
  • hey yeah this seems to go into the direction i look at, maybe you can refer a few books other than DDD, which address this problem. Maybe you can add a few quotation where Evan think about the dilemmas in DD and possible ways to resolve them (Or you refer the book-positions where i can find that)..... However, you wrote about a dilemma. Maybe i have to keep using the controller/Service solution? And there is no solution without them, no solution for the LoD (Law of Demeter), that exists only for a few separate problems and not for the 90% other (main) code? Commented Mar 25, 2021 at 17:29
  • Chapters 2, 4, 5, 6, and 9 seem relevant, but may not make sense out of context. I don't think you need "a few other books" but that's your call. The way this question is written and your responses to others here make it difficult (for me) to tell the main goal: getting better at OO design or arguing for the procedural approach in a public forum. You have my best advice for the former. Good luck! Commented Mar 26, 2021 at 1:23
  • You have good eyes. Let me say its something between it. There still exists cases "collaborating classes" in that way i descriped and to 90%. I think there doesnt exist a solution like encapsulating behaviour and data or a valid LoD; but @RobertBräutigam claims that there exists such a way/solution. So the goal is to see the solution, to see that i can express all in OO i want to -> i want to get better in OO; but on the other hand it seems for me that there doesn't exist that and don't argue for the proc. approach directly , but for that, that OO only exists theoretically and not in real. Commented Mar 26, 2021 at 2:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.