Simplifying dependency injection

Dependency injection at first seems like a complex topic, but for the most part it is a simple concept. It is a design pattern aimed at making your code within your applications more flexible so that you can swap out certain functions when needed. The idea builds around setting up dependencies between classes in an application so that each class only interacts with an interface or base/abstract class. This gives you the freedom to override different methods on each platform when you need to fill in native functionality.

The concept originated from the SOLID object-oriented design principles, which is a set of rules you might want to research if you are interested in software architecture. The D in SOLID stands for dependencies. Specifically, the principle declares that a program should depend upon abstractions, not concretions (concrete types).

To build upon this concept, let's walk through the following example:

  1. Let's assume we need to store a setting in an application that determines if the sound is on or off.
  2. Now let's declare a simple interface for the setting: interface ISettings { bool IsSoundOn { get; set; } }.
  3. On iOS, we'd want to implement this interface using the NSUserDefaults class.
  4. Likewise, on Android, we would implement this using SharedPreferences.
  5. Finally, any class that needs to interact with this setting would only reference ISettings so that the implementation could be replaced on each platform.

For reference, the full implementation of this example would look like the following snippet:

public interface ISettings
{
  bool IsSoundOn
  {
    get;
    set;
  }
}

//On iOS
using MonoTouch.UIKit;
using MonoTouch.Foundation;

public class AppleSettings : ISettings
{
  public bool IsSoundOn
  {
    get
    {
      return NSUserDefaults.StandardUserDefaults
      .BoolForKey("IsSoundOn");
    }
    set
    {
      var defaults = NSUserDefaults.StandardUserDefaults;
      defaults.SetBool(value, "IsSoundOn");
      defaults.Synchronize();
    }
  }
}

//On Android
using Android.Content;

public class DroidSettings : ISettings
{
  private readonly ISharedPreferences preferences;

  public DroidSettings(Context context)
  {
    preferences = context.GetSharedPreferences(context.PackageName, FileCreationMode.Private);
  }

  public bool IsSoundOn
  {
    get
    {
      return preferences.GetBoolean("IsSoundOn", true");
    }
    set
    {
      using (var editor = preferences.Edit())
      {
        editor.PutBoolean("IsSoundOn", value);
        editor.Commit();
      }
    }
  }
}

Now you would potentially have a ViewModel class that would only reference ISettings when following the MVVM pattern. It can be seen in the following snippet:

public class SettingsViewModel
{
  private readonly ISettings settings;

  public SettingsViewModel(ISettings settings)
  {
    this.settings = settings;
  }

  public bool IsSoundOn
  {
    get;
    set;
  }

  public void Save()
  {
    settings.IsSoundOn = IsSoundOn;
  }
}

Using a ViewModel layer for such a simple example is not necessarily needed, but you can see it would be useful if you needed to perform other tasks such as input validation. A complete application might have a lot more settings and might need to present the user with a loading indicator. Abstracting out your setting's implementation has other benefits that adds flexibility to your application. Let's say you suddenly need to replace NSUserDefaults on iOS with the iCloud function; you can easily do so by implementing a new ISettings class and the remainder of your code will remain unchanged. This will also help you target new platforms such as Windows Phone, where you may choose to implement ISettings in a platform-specific way.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.213.235