• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
Question by ronronmx · Feb 18, 2013 at 10:36 PM · inheritanceclassespolymorphism

Polymorphism question for my custom class

Hi all,
I have used polymorphism in the past, but not with anything too complicated. This time, I have a class which stores a bunch of info about the object I pass into it, and I wrote a very similar class for a different type of object in another script, which seems like a waste of time and typing since I could probably make a master class, and use copies of it instead of writing it over and over again, but I'm not 100% it's a good idea for this specific class.

Here is the first class I wrote:

public class HUDElement { // Store object information for the passed GameObject private HUDSettings.HUDType _hudType; private HUDSettings.NGUIType _nguiType; private GameObject _hudObject; private GUITexture _gTexture; private bool _hudState; private bool _isControl;

     public HUDElement( HUDSettings.HUDType type )
     {
         this._hudType = type;
     }
     
     public void Init( GameObject go, bool state, bool isControl, HUDSettings.NGUIType nguiType )
     {
         _hudObject        = go;
         _gTexture        = go.GetComponent();
         _hudState        = state;
         _nguiType        = nguiType;
         _isControl        = isControl;
         
         // Toggle HUD Element to its default starting state,
         // this prevents HUD elements that are turned off by default from being activated on Initialization
         Toggle( state, true );
     }
     
     public void Toggle( bool isActive, bool isInit = false )
     {
         if( _hudType == HUDSettings.HUDType.BOOST && isInit == false )
         {
             if( _hudObject ) _hudObject.SetActiveRecursively( isActive );
         }
         else
         {
             if( _nguiType != HUDSettings.NGUIType.NONE && _hudObject )
             {
                 switch( _nguiType )
                 {    
                     case HUDSettings.NGUIType.UISlicedSprite:
                         var uiSliceSprites = _hudObject.GetComponentsInChildren();
                         foreach( UISlicedSprite s in uiSliceSprites ) s.enabled = isActive;
                         break;
                         
                     case HUDSettings.NGUIType.UISprite:
                         var uiSprites = _hudObject.GetComponentsInChildren();
                         foreach( UISprite s in uiSprites ) s.enabled = isActive;
                         break;
                 }
                 
                 // No need to toggle the gameObject itself nor check for a GUITexture, so let's stop here.
                 return;
             }
             
             if( _gTexture != null ) _gTexture.enabled = isActive;
             else if( _hudObject ) _hudObject.active = isActive;
         }
     }
     
     public HUDSettings.HUDType HudType{ get{ return _hudType; }}
     public HUDSettings.NGUIType NGuiType{ get{ return _nguiType; }}
     public GameObject HudObject{ get{ return _hudObject; }}
     public GUITexture GTexture{ get{ return _gTexture; }}
     public bool HudState{ get{ return _hudState; } set{ _hudState = value; Toggle( _hudState ); }}
     public bool IsControl{ get{ return _isControl; } set{ _isControl = value; Toggle( _isControl ); }}
     
 }
 
 private HUDElement[] HUDElements = new HUDElement[(int)HUDSettings.NumOfHUDTypes];


 private HUDElement _mainHUD = null;
 public HUDElement MainHUD
 {
     get
     {
         if( _mainHUD == null ) _mainHUD = HUDElements[(int)HUDSettings.HUDType.MAIN];
         return _mainHUD;
     }
 }
 
 private HUDElement _menuHUD = null;
 public HUDElement MenuHUD
 {
     get
     {
         if( _menuHUD == null ) _menuHUD = HUDElements[(int)HUDSettings.HUDType.MENU];
         return _menuHUD;
     }
 }
 
 // more properties.......

}

Next, here's the second - similar - class I wrote for another type of object:

public class ControlElement { private ControlSettings.ControlType _controlType; private GameObject _controlObject; private bool _controlState;

     public ControlElement( ControlSettings.ControlType type )
     {
         _controlType = type;
     }
     
     public void Init( GameObject go, bool state )
     {
         _controlObject    = go;
         _controlState    = state;
         
         // Toggle this Control Element to its default starting state,
         // this prevents Control elements that are turned off by default from being activated on Initialization
         Toggle( state );
     }
     
     public void Toggle( bool isActive )
     {
         _controlObject.active = isActive;
     }
     
     
     public ControlSettings.ControlType ControlType{ get{ return _controlType; }}
     public GameObject ControlObject{ get{ return _controlObject; }}
     public bool ControlState{ get{ return _controlState; } set{ _controlState = value; }}
 }
 
 private ControlElement[] ControlElements = new ControlElement[(int)ControlSettings.NumOfControlTypes];


     private ControlElement _accelControl = null;
 public ControlElement AccelControl
 {
     get
     {
         if( _accelControl == null ) _accelControl = ControlElements[(int)ControlSettings.ControlType.ACCEL_BTN];
         return _accelControl;
     }
 }

 private ControlElement _brakeControl = null;
 public ControlElement BrakeControl
 {
     get
     {
         if( _brakeControl == null ) _brakeControl = ControlElements[(int)ControlSettings.ControlType.BRAKE_BTN];
         return _brakeControl;
     }
 }
 
 // more properties...

}

So my question is, given the differences between those 2 classes, is it still a good idea to use polymorphism with copies of 1 master class?

Thanks for your time guys!
Stephane

Comment
dubbreak
Bunny83

People who like this

2 Show 0
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
Best Answer

Answer by dubbreak · Feb 18, 2013 at 10:58 PM

In my opinion. No. I don't see a clear relationship. It's not a good use of polymorphism.

Using inheritance for the sake of reusing a few methods that might be the same (so you can use polymorphism) is a perfect example of when not to use it. Inheritance should only be used in clases with a clear is-a realtionship. E.g. an apple is a fruit (very simple) or recently I had a black jack hand which extends a card hand (collection of cards belonging to a player) that has special methods added to it that are black jack only (such as the hand value). It was clear that is was a sub case of the general case and the base case had other legitimate ways to extend it(e.g. poker hand).

Using inheritance for the sake of polymorphism alone is an anti pattern and an abuse of OOP. I worked with someone that did that, and his stuff was not maintainable. You should look at using an interface or some kind of class composition rather than inheritance if you are worried about code duplication.

Here is a good stackoverflow post on composition vs inheritance.

Inheritance can result in some pretty nasty lock in that's difficult to refactor out. This becomes especially apparent when it gets miss-used. The end uses aren't actually related so you end up with them diverging and the base class not actually working for either very well. I remember a base communication class that should have been an interface (to guarantee each communication type had the agreed on interface to get and send data). Instead is was a base class that locked in certain behavior and created some horrible coupling that was very difficult to fix.

Comment
ronronmx
Bunny83

People who like this

2 Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image dubbreak · Feb 19, 2013 at 03:07 AM 1
Share

Just a follow up: I'd like to say your question was a good question. Polymorphism is a really cool concept. However it is prone to misuse. I've seen people with "20+ year experience" misuse it (of course I've also seen people still in University catch the misuse of various language features of people way senior to them.. I've also had co-op students teach me a thing or two.. ). It's quite admirable that you'd stop to ask, "Hey, is this a good use for this concept?" That shows a lot more restraint than your average person and the type of drive to learn and understand that is seen in great coders (actually great people in any subject).

I remember seeing some code in which the guy must have just learned about function pointers, so they were used everywhere (and none of the uses were appropriate). It's like marketing guy learning to do the apple fake reflection thing and then using it in every piece of marketing material possible. Every logo, every product picture with a "reflection"!! The toughest thing is learning the appropriate time to use features. It's nice to have a new tool in the toolbox, but don't let that shiny new hammer make every problem look like a nail.

I personally abuse linq to no end. Like someone who thinks all things can be solved by a regex I tend to attack most problems with linq if it's remotely possible I can use it (favorite tool in the box I guess?).

avatar image ronronmx · Feb 19, 2013 at 08:52 PM 0
Share

Thanks a lot for your explanation, made lots of sense and was very helpful. It's not always clear to me when to/not-to use Polymorphism, and since I hate code duplication, I always try to find a way to get rid of it. But maybe sometimes, code duplication is a better choice.

avatar image dubbreak · Feb 19, 2013 at 09:57 PM 0
Share

I think a good rule of thumb on code duplication is: if you are copying and pasting large chunks of code from one area to another, you're doing something wrong.

Lots of basic stuff is going to look similar and like duplication, but in reality that's just the nature of wiring stuff up. It's all repetitive. It's duplicating algorithms and complex logic that should be avoided. Separation of concerns but also centralization.

Sometimes what's needed is a util class with some static methods that get used frequently throughout the code. Sometimes an extension method is the right choice. I found I was making sprites blink a lot in a project. So I wrote a blink extension methos I can use on basically any game object. That way I'm not forced to extend from some base class just to get that behavior. Works on ngui items, my own items etc.

One really good way to learn is going back over your code 6 months down the road and seeing if you'd do anything differently with what you know now. Not necessarily change it (if it ain't broke don't fix it), but file a mental note. One of my friends often says, "Hey that was me 6 months ago, I can't defend what that guy did. I'm sure he had a reason, but I wouldn't do it that way now." Constructive code reviews are good as well (i.e. not nitpicking on formatting and naming conventions, but focusing on overall structure). Different people approach problems differently, and seeing things from a new perspective can be eye opening. Downside is that requires peers and they aren't always readily available. I always found architecture meetings incredibly interesting (a bunch of engineers debating the best solution to a problem can be quite fun.. well if it's an ego free environment).

And at the risk of dragging on.. my card example, while a good use of inheritance it really isn't of any use if you aren't making multiple child classes. I already had the base card code and base card game logic, so extending it made sense. If I was making a blackjack game from scratch I'd have to evaluate whether there was value in separating a base class from the blackjack specific code. When writing games you want to be efficient. If you are never going to resuse the base class it's over-engineering. If I really needed to I could decompose the class into a base and child class later (and that would be the right thing to do.. wrong thing would be copy/pasting then changing what I needed for the other game). Sometimes shortcuts aren't bad (and sometimes they are more readable). In the end you want something readable and maintainable. Simple is good, it's just sometimes harder than writing complex code.

avatar image ronronmx · Feb 20, 2013 at 05:21 AM 0
Share

Yes having a util class is definitively a good thing. I have an extension methods class that I use from GameObject stuff, but I keep forgetting about it and I don't add new methods to it as often as I could hahaha

I started learning programming from scratch in 2010, and since then, I have looked at my code and re-wrote the whole structure for my game 3 times...it went from crappy beginner code to okay wannabe code to decent amateur code, and I'm pretty happy with it now :)

Thanks for all the examples and advice, much appreciated!!!

avatar image dubbreak · Feb 20, 2013 at 04:39 PM 0
Share

Glad I could be of help and happy to hear you are coming along. Regardless of level, people that care about their craft and are always looking to improve are the best to work with (and unfortunately rare).

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

10 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

An OS design issue: File types associated with their appropriate programs 1 Answer

Calling a method of a class that is a part of another class? 1 Answer

Abstract class question 1 Answer

The name 'Joystick' does not denote a valid type ('not found') 2 Answers

How to inherit from two classes? 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges