Please Encapsulate Your Fields

The inspector is Unity’s one stop shop for fiddling with game objects’ values and is one of the used windows of the Unity editor. The default inspector picks up the properties to display using a set of simple rules (read here).

While the inspector provides an easy way for programmers and designers to easily edit gameplay elements, it does so many times at the cost of code encapsulation. This post shortly discusses this issue and suggests a simple, built-in solution that Unity provides, to better encapsulate your code.

OMG It’s all public !

Consider the following piece of script code:

using UnityEngine;
using System.Collections;

public class LaserObstacle : MonoBehaviour
{
    public int DamageAmount;
    public float DamageDuration;
    public int NumberOfBeams;

    public GameObject LaserPrefab;

    // Implementation details ...
}

This results in an inspector that lets you edit all the public fields you exposed in script:

Inspector

 

 

 

 

In smaller projects this may not be such a big issue, but the problem is that this breaks the object’s encapsulation. Once the code base grows and you have thousands of scripts, having all their internal “guts” exposed to all other code can cause serious issues (what implications will changing this piece of code have ?)

I don’t blame us all for writing code that’s all public – it’s what we’re all used to seeing for years in many code samples and most of the online resources I’ve seen. I believe the reason for this is that samples usually focus on succinctly getting something done and not dealing with the correct structuring of code.

[SerializeField] to the rescue

So we want to still allow editing scripts through the editor while having the code encapsulated, exposing only what is needed (the code’s public API).

In order to achieve this we can follow this pattern:

  • Set fields on MonoBehaviours to private.
  • Decorate fields that should be exposed in the inspector with the [SerializeField] attribute.
  • (Optional) expose public properties on the script to allow accessing its internal state fields.

The code shown above could be rewritten like so:

using UnityEngine;
using System.Collections;

public class LaserObstacle : MonoBehaviour
{
    [SerializeField]
    private int damageAmount;

    public int DamageAmount
    {
    	get { return damageAmount; }
    }

    [SerializeField]
    private float DamageDuration;
    [SerializeField]
    private int NumberOfBeams;

    [SerializeField]
    private GameObject LaserPrefab;

    // Implementation details ...
}

What did we gain here ?

  1. The inspector for the script looks the same (we can edit it in the same way).
  2. The class does not expose all fields as public.
  3. We can expose the data we want using properties (can also make a property read only by controlling its get/set accessors).

I can not think of  any downside to such code, aside from the extra typing involved. I believe I will adopt this style from now on when creating new scripts.

EDIT:

Lucas from Unity kindly replied to me (on Twitter), saying that aside from typing more, there’s no other downsides:

Screen Shot 2014-12-22 at 00.03.13

Conclusion

I’ve shown a simple, built-in way, that does not require creating new inspectors or custom editor code, that allows us to have the best of both worlds – working with inspectors and keeping our code encapsulated. I would love to hear any comments or other suggestions whether there are any disadvantages to this code that I clearly missed. Feel free to comment and share you thoughts !

Resources

This entry was posted in Unity. Bookmark the permalink.

5 Responses to Please Encapsulate Your Fields

  1. bradur says:

    I recently started doing this myself. It makes debugging stuff a whole lot easier!

  2. Jakub Pukovec says:

    I also recently started to use [SerializeField] attribute and since the time I have much better personal feeling encapsulation is not harmed.
    Also it’s currently stated in MSDN Member Design Guidelines that fields should never be public or protected. Only private, otherwise it breaks principle of encapsulation.
    source: https://msdn.microsoft.com/en-us/library/ms229057(v=vs.110).aspx

    If a field needs to be set as public or protected, property or method should be used instead.

    You can see the SerializeField technique in many Unity official scripts.

  3. Joe Bain says:

    This is a nice tip, I don’t like having to make everything public in order to provide editor access. I have a question though – if I want to make an editor extension for a class like this, how do I access those members, now that they are private or protected?

    • Joe Bain says:

      Ooh, I figured it out. You can access the values through the serializedObject property. http://answers.unity3d.com/questions/683170/access-serialized-field-in-custom-editor.html Don’t forget to do serializedObject.ApplyModifiedProperties() too!

      • Lior Tal says:

        One way is to use the serializedObject as you mentioned. Unity’s serialization system doesn’t care about private or public fields.. If a field is serializable (well, some public fields get serialized by default) it will get written into the SO. As you suggested this will work but you lose the type safety, auto complete and all other fancy features..
        Another (hacky) option that could work (never tried it though) is to compile your components into an assembly of their own. Mark their fields as internal instead of private. Then use the InternalsVisibleTo attribute to make these fields accessible by another assembly.. Super hacky and really too much i guess..
        Need to think about it as there may be other, more elegant solutions..

Leave a Reply

Your email address will not be published.