Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Using events within interfaces to achieve loose coupling.

Discussion in 'Scripting' started by Freaking-Pingo, Jun 19, 2014.

  1. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    I am trying to become better at programming loosley coupled code, though I have stumbled upon a design which I am not sure is good practice, and I would like to know from you guys whether this approach is good practice.

    My idea is to make an interface for NPC's who can be possible targets. Targetable NPC's would have to implement this ITarget interface:

    Code (CSharp):
    1. public delegate void VulnerabilityHandler();
    2.  
    3. public interface ITarget {
    4.  
    5.     event VulnerabilityHandler vulnerabilityChanged;
    6. }
    The idea with this interface is that all targetable NPC's must implement a vulnerability event, which other classes can subscribe to and become informed if vulnerability is changed on that particular NPC.

    However, when implementing this interface into a class, I am required to write a lot of extraordinary code.

    Code (CSharp):
    1. public class Player : MonoBehaviour, ITarget {
    2.  
    3.     event VulnerabilityHandler vulnerabilityChangeEvent;
    4.     event VulnerabilityHandler ITarget.vulnerabilityChanged
    5.     {
    6.         add
    7.         {
    8.             vulnerabilityChangeEvent += value;
    9.         }
    10.         remove
    11.         {
    12.             vulnerabilityChangeEvent -= value;
    13.         }
    14.     }
    15. }
    For every event, I wish to implement I am required to implement the above code, which I find rather extensive. I personally believe this is a good approach, because it allows for NPC's to have loose coupled targets, though I am pondering if there exist better solutions.
     
  2. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    It's not that much code, is it? It's a standard declaration and a standard property with a minimal accessor/mutator.
     
  3. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    Interfaces in general, especially event interfaces (as long as such interfaces are shared accros multiple classes) are always a good idea and good practice. Dont worry about the extra code, it's definitly an OOP and good layout.

    Furthermore, the other choice would be using an abstract class but this does introduce limitations in your inheritance hierarchy.
     
  4. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    Perhaps it is not that much, when you put it like that. I often just use code which requires fewer lines, mostly because I rarely use getters / setters. I guess thats another aspect I might also have to look into.

    I guess the limitation in the abstract classes is because you only can inherit from a single class?
     
  5. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    Exactly. Other than that, deriving multiple different classes from a dedicated base class is considered bad design. ;)
     
  6. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    What do you mean by this? That's the entire purpose of having a "base" class, to be derived from it. I agree that overuse/deep/complex hierarchies are typically bad, but I wouldn't dream of drawing the line at "multiple", which I interpret as "more than one".

    Anyway, for the OP, check out the concept of "composition". You can do super flexible stuff with that.
     
  7. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    I already thought that my previous post would be missunderstood. What I mean is, that it fully depends on what that certain baseclass represents. In terms of MonoBehaviours its completly legit since they represent the base of every behaviour, attachable to a GameObject.
    What I mean is that something so dedicated and single-usefull like vulnerability shouldnt be represented by a base class. Something this dedicated should always be moved to an interface. In contrast, a base class of type "ControlledEntity" (or sth similar) which would represent monsters/NPC's and what-so-ever would be legit. Letting such a base class implement a vulnerability interface would be considered good design.

    /E: What I meant with "multiple different classes" are classes which derive from a certain dedicated base class, tho, they dont share any similarity, neither with the base class nor with each other, falling out of context.
     
  8. zaxvax

    zaxvax

    Joined:
    Jun 9, 2012
    Posts:
    220
    System like this is very fast running, and the only problem with it is modifications. Changing interface will make broken all classes that implement this interface. You might want to create another interface version 2.0 and you can end up with lots of interfaces or lots of classes to change when you change your single interface. If you decide to add some "features" in the future it can become time consuming.

    If it's an issue for you, then you can use an event system based on broadcasts, event managers and things like that.
    If not then it's a great system.
     
  9. shaderop

    shaderop

    Joined:
    Nov 24, 2010
    Posts:
    942
    But that is exactly what a MonoBeahviour is, a base class for "multiple different classes" that don't share any similarity. And you just cited MonoBehaviour as an example of good design.
     
  10. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    Nice one, but obviously, anything deriving from MonoBehaviour shares a big similarity, it is a behaviour, attachable to any GameObject! ;D
    Furthermore, MonoBehaviours are not dedicated and force you into one single meant functionality.
     
  11. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    Yeah, I think I get your point. If I have implemented the ITarget interface in five different classes, if I wish to further add features in the ITarget interface, I am also required to modify the five other classes.

    I am however not quiet sure of your solutions. Isn't broadcast often frowned upon, because of using magic strings (Executing functions based on strings rather than using references)? How would you design an event manager to overcome this problem, I can't seem to grasp my head around a solution for such issue.
     
  12. shaderop

    shaderop

    Joined:
    Nov 24, 2010
    Posts:
    942
    I assure you that I'm not trying to impress you. But thank you anyways.

    And any set of classes that inherit from any single base class—even an empty one—share the big similarity that they also implement a behavior of some sort. That is the point of classes in OO, you see, which is to implement behavior. This similarity you're imagining in all MonoBehaviour-derived classes is so broad as to be useless. It's like you likening yourself to a sea urchin. Both of you are members of the animal kingdom, but that says very little else about either of you.

    So MonoBehaviour is both specialized enough that classes derived from it are similar enough to makes them okay in your OOP design book, and, at the very same time, its general purpose enough that it doesn't force derived classes to be similar. So, according to your definition, it's both good (specialized) and bad (too broad).

    It can't be both at the same time. Care to make a pick?
     
  13. shaderop

    shaderop

    Joined:
    Nov 24, 2010
    Posts:
    942
    Pub-sub messaging systems don't need to rely on magic strings. There's a nice open source library called "TinyMessenger" that does pub-sum messaging quite well, and it's all in a single C# file. I have been using it on several projects with great success. I wrote about my experience with it a while back.
     
    _met44 likes this.
  14. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    I guess you should re-read my previous posts.
    To explain it a bit better:

    1. Deriving from an empty base class does not implement a behaviour in any way.
    2. Deriving from MonoBehaviour does implement the fact of being a behaviour. It doesnt matter what the derived classes acctually do and how different they are, they always stay the big global type, called behaviour.
    3. The similarity they share/implement are in no way useless. Its global, no matter what you derive from it, its always obviously attachable to a game object.
    4. Regarding to specialized nor broad. MonoBehaviour is nothing of both. Anything deriving from MonoBehaviour does obviously cleary mirror the fact of being a behaviour. It is clearly not specialized since you always maintain the main and global similarity, but infact can build fairly different classes from it. Still, it clearly stays a behaviour.

    I guess its hard to explain what im up to say, tho, I clearly get your point. Its true that any class implements some type of behaviour when it derives from another. In terms of being vulnerable, its something so specialized, in general, a so specialized property of an object to better be an interface.
     
  15. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
    in what way is this decoupled?
     
    shaderop likes this.
  16. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    I see what Sharp Development is getting at and I think it might just come down to this use case. Making a base class wouldn't allow an NPC to be vulnerable and also be something else.
     
  17. shaderop

    shaderop

    Joined:
    Nov 24, 2010
    Posts:
    942
    I would have, but then you said:
    Not exactly a glowing endorsement by the post's own author.

    You use the word "behavior" as if it means something specific, and yet you directly follow that with explaining that derived classes are free to do whatever they want to do. What's the use of "being a behavior" in OO design terms if it doesn't carry any constraints or impose any, for lack of a better word, actual behavior?

    And why should I care or even want a type to be attached to GameObject if it's not going to interact with rendering, physics, or user input directly? Why should I want a type to inherit from MonoBehaviour if all it is doing is communicating with a server or logging diagnostics? Yet that's what we are often forced to do just to be able to function in Unity's runtime.

    You keep going around the same merry-go-around. You say that deriving from MonoBehaviour is important because the derived type is now a behavior as if that somehow matters and then go back to saying that that still allows the derived class to do whatever it wants as if being a behavior no longer matters anymore. Are you practicing some sort of code mysticism here where any class is always is and isn't, always broad and yet specialized, always "is nothing of both"? Because that's groovy, man. But you'll need to share your stash because we're not at all on the same wavelength.

    I think that whatever point you're trying to make would go down a lot smoother and have a chance of actually making sense if you would stop using MonoBehaviour as an example of good OOP design, because it simply isn't. You'll not see such a monolithic class design in your Gang of Four or your Martin Fowler or in your Domain Driven Design books. It's a compromise born out of the constraints of a language and the desire to present users with an API that is easy to understand and doesn't feature dozens of interfaces that need to be composed together to make things work. And that's just fine. OO is a means to an end, not an end by itself.


    That's a very good point, actually.
     
    sootie8 likes this.
  18. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    I have an additional question in regards to interfaces. I have now created an additional class that makes use of my newly created interface ITarget.

    The class looks like this:

    Code (CSharp):
    1. public class Poltergeist : Monobehaviour {
    2.  
    3.     void Start()
    4.     {
    5.         SetNewTarget(Player.Instance.gameObject);
    6.     }
    7.  
    8.     void SetNewTarget(GameObject newTarget)
    9.     {
    10.         ITarget iTarget = (ITarget)newTarget.GetComponent(typeof(ITarget));
    11.         if (iTarget != null)
    12.         {
    13.             iTarget.vulnerabilityChanged += TargetVulnerabilityChanged;
    14.             target = newTarget;
    15.         }
    16.     }
    17.  
    18.     void TargetVulnerabilityChanged()
    19.     {
    20.         // Do action upon change
    21.     }
    22. }
    What I am not sure of is the GetComponent and typecast of (ITarget) The fact that I have some GameObject, and wish to make use of its (possible) interface, am I really required to make the GetComponent(typeof(ITarget)) and then perform a typecast? Is this how its usually used?
     
  19. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    I have always thought that MonoBehaviour was a good example of OOP. All classes that wish to be attached to a GameObject within a scene in Unity must derive from MonoBehaviour, because MonoBehaviours contains important methods and information that allows the script to be considered "Attached" to a GameObject.

    That not how I see it. We can agree that a majority of classes will in the long run derive from MonoBehaviour, but not them all. Classes that are independent of the scene, is not required to derive from MonoBehaviour. In a more general sense, you can state that there exist two "Main" base classes. MonoBehaviour and Non-MonoBehaviour. There of course, does not exist a Non-Monobehaviour base class, because there is no information to be shared.

    I tend to be bad at sharing written information, so I have created a simple illustration to show what I mean.

     
  20. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    shaderop makes the excellent (and frustrating) point that in order for non-MonoBehaviour code to execute it must rely on some call from MonoBehaviour-derived code.
     
  21. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    That is true, but that does not necessarily mean that Monobehaviour is poor OOP? As far as I understand, all applications have a single main thread, thus, there is always required a "first mover" in order for other scripts to be executed. Would that mean that other attempts of OOP is poorly done, because they are dependent on the main thread? Or is MonoBehaviour poor OOP because a base-class is used as "first mover".
     
  22. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    Im not quiet sure what you say... MonoBehaviour is a base class and any type deriving from it does infact describe some "behaviour" of a game object. Thats acctually what any type, derived from it, has in common. It IS a behaviour and it is meant to be attached to a game object... Of course, any derived type is aswell constraint by the parent type, just take instantiation as an example.

    And where did I say that you MUST derive from MonoBehaviour? It was just an example to explain my point. Noone ever said that you are forced into using it in any way...

    No we are definitly not on the same wavelenght. I've not said in any of my posts that you MUST derive from MonoBehaviour nor did I say it is important to derive from it. It was a basic example and the word behaviour was infact used by me to describe what any MonoBehaviour child has in common, it is used represent a behaviour attachable to a game object. Thats the similarity you've asked for and I pointed out. It is of course allowed to do whatever it wants, but it is, as you've pointed out above, constraint by its parent class. That infact means, that the sentence "doing whatever it wants" is constraint by the rules the parent sets.

    I think that whatever point you're trying to make would go down a lot smoother and have a chance of actually making sense if you would stop using MonoBehaviour as an example of good OOP design, because it simply isn't. [/QUOTE]

    And once again, quote my words where I said a MonoBehaviour is an example of good OOP design. I've acctually only used it as an example to point out that a type such as MonoBehaviour does obviously make any class derived from it a behaviour, a similarity all those classes do definitly have in common. To come back to the OP's interface, such a minor, specialized property of an object as base class for hundrets or only dozens of classes just doesnt make any sense. It should stay an interface since the property it represents is just so specific and cant really represent or describe an object enough.
     
  23. shaderop

    shaderop

    Joined:
    Nov 24, 2010
    Posts:
    942
    You keep refusing to pin down a definition for this "behavior" you keep parroting over and over. Seems like what you mean by it is "doing S***." So any class derived from MonoBehaviour has the very special and (in your eyes) important property of "doing S***." My point was that any class in OOP, regardless of its base class or if it has a base class at all, is there to "do S***."

    You didn't. I did. And I even gave an example of where one has to derive from MonoBehaviour when it won't make any sense design-wise just to be able to function inside the runtime.

    The point was that good OOP design shouldn't force a class to derive from another unless it implements some sort of is-a relationship. In the case of MonoBehaviours that is-a translates to "is-a a container of code", which is a relationship that is so broad that it's not useful in terms of design.

    And I find it extremely hard to believe that you have't run into a situation where you had to derive a class from MonoBehaviour just to get some bit of code to run despite not being even visible in the game world. You'll have to be a total n00b not to have seen that yet.

    There you go on that MonoBehaviour-beahvior-GameObject merry-go-around again. You're still not making much sense.

    Sure. Follow along if you can.

    So, deriving from a base class is bad design.

    Deriving from a base class is bad design, but not in the case of MonoBehaviours. This is a "legit" use case, i.e. not bad, i.e. good.

    Therefore, as far as being a base class, MonoBehaviour is an example of good design.

    If you had a change of heart since those two posts and now you're of the opinion that MonoBehaviours are in fact not examples of good OOP design, then that's great. I'm glad we can agree on something.
     
  24. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    This bollocks starts to seriously make me angry. Either you just try to somehow proof me wrong, or you just simply dont want to understand my words.
    I am not able to pin down the behaviour since it CANT BE PINNED DOWN! A class derived from MonoBehaviour simply represents and describes some kind of behaviour. There is simply no other word for it, so I dont quiet get why I do have to iterate over this over and over again... Your imagination should be good enough to think of AI, movement, attacking, whatsoever when talking about a behaviour in terms of deriving from MonoBehaviour.

    See, I didnt so why do you try to quote me on that? Thats simply a point you put in but we acctually never really discussed about. You act like I throw it in, try to prove me wrong while I had never said such a thing. Funny.

    On one site I can see your point here, on the other site, anything you derive from MonoBehaviour shares a relationship, the fact of needing to be attached to a gameobject due to whatsoever reason.

    Wasnt the point. Like I said, even than it shares the similarity of being needed to be attached to a gameobject. It is out of scope, never said by me and never said to be OOP by me in any way. If its bad design or not was aswell never said by me...

    Furthermore, in this case MonoBehaviour essentially works as your entry point, which is considerable similar and comparable to a programs Main() method. Oh, hm. Well, hm, so Windows and any unix system are aswell bad. Lets go further to bios and hardware, why not even down to computer technique in general, since it seems all are wrong considering all offer some kind of entry point. Hmpf...


    Never said that. Quoting a missunderstood sentence which was explained later is somewhat bad design.


    Never said that.

    Again, never said that nor did I ever discuss about MonoBehaviour's being OOP or not. I've not had a change of heart, I've just more accurately explained what I meant with my first posts.



    Im not quiet sure why you continue this since you obviously dont want to constructivly discuss right here, neither trying to get the point somehow, quoting me on stuff I never said nor meant just to somehow prove me wrong for whatsoever reason. So, how long should this take?
     
    Last edited: Jun 19, 2014
  25. shaderop

    shaderop

    Joined:
    Nov 24, 2010
    Posts:
    942
    I am trying to prove you wrong. That's how debates work; by proving the other party wrong.

    I'm trying to understand, but that's not being helped by your iffy command of the language as demonstrated in this thread so far.

    I'll break it down for you once more.

    You are saying that deriving from a base class is bad design. Given the context, it is more than reasonable to assume that you meant OO design. Not architectural design, not industrial design, not integrated circuits design. But OO design.

    Here you point out that MonoBehaviour is excepted from your prior statement, i.e. that MonoBehaviour is not one of the baddies. In common speech (as opposed to, say, legalese) this communicates to the listener or reader that MonoBehaviour is the opposite of bad OO design, i.e. an example of good OO design.

    QED. That's your saying that MonoBehaviour is an example of good OO design. Got that?

    If you want to redefine how communication works between humans then I'm sorry but I'm not going to play along. That's how I understood what you said and that's how most reasonable people would understand it. Maybe you didn't mean to say what you said, but that's what you ended up saying anyways.

    I'm totally fine if you didn't mean to say the above. Miscommunication happens all the time. But don't accuse me of putting words in your mouth.

    That's an invalid comparison because defining a method called "Main" doesn't involve any kind of inheritance.

    The definition of quoting is to "repeat or copy out (words from a text or speech written or spoken by another person)." So it's impossible for me to quote you on things that you didn't say. You conceding that I actually quoted you entails you admitting to actually saying the quoted words. It's that language and communication thing that you keep trying to redefine.

    Also it's not possible for you to not say something and not mean it at the same time. Not meaning it requires saying it.

    And I hate to break it to you, but using your own words to prove you wrong is a perfectly valid form of debate.
     
    sootie8 likes this.
  26. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    656
    Shaderop: You have a signature saying "hire me!"
    First of all, if you actually want a debate, you might want to work on your attitude. You sound very arrogant and condescending from the get go. That may be a "perfectly valid form of debate" but it won't take you far. You are not trying to understand "the essence" in this debate. You are trying to pick a fight by judging single sentences and words by their strict meaning. You communicate in binary terms, instead of implementing a degree of fuzzy logic.
    Don't. It is bad publicity for you. Even if you are skilled at what you do.
     
  27. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    I think his attitude was fine. He didn't get angry or troll and all the points he brought up are perfectly valid.
     
  28. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    656
    And that is why I didn't say "You sound angry and you are a troll", but said "You sound very arrogant and condescending".
    One can be right, skilled and very pretty, and still walk alone. Anyways...
     
  29. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Who's judging sentences and words by their strict meaning now? :)
     
  30. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    656
    Oh well, one can also get too fuzzy ;) I totally agree, he didn't get angry and he didn't troll. So by those standards alone, his attitude is fine!
    But anyways, who am I to judge anybody, right? It really isn't my style. I just felt the need to defend a person against what I considered bad manners. And the thread already felt derailed.
     
  31. shaderop

    shaderop

    Joined:
    Nov 24, 2010
    Posts:
    942
    Thanks, man. I do appreciate it :)

    I think you already did. See the following:
    Sounds to me like you've passed judgement and shared it with the world.

    I think that most people would agree that calling a person "arrogant and condescending" and attacking someone's character instead of their arguments is the definition of bad manners.

    Thanks for the link, but if you care to go over it once or twice you'll notice that Fuzzy Logic doesn't equate with lapses of logic, which was my issue with the other person's posts.

    And thanks for your advice on employability, but I've been doing fine so far without it. I'm sure you'll love it when you hire someone and he or she employs your version of fuzzy logic on your requirements and deadlines. My clients, on the other hand, are used to stricter standards.