简体   繁体   中英

Should I pass an app-wide object into objects that need it, or should I use a singleton?

In my specific situation, I am passing a "facebook" object (ie an instance of MonoTouch.FacebookConnect.Facebook) down through nested view controllers, and it is adding a decent bit of code to the project. There is always exactly one instance of the object after it is instantiated in the AppDelegate, and it is used in most of the view controllers in the app. All of the view controllers that utilize the facebook object have something like this at the beginning:

public class MyViewController : UIViewController
{
    Facebook facebook;

    public MyViewController (Facebook facebook)
    {
        this.facebook = facebook;
    }
    // ...
}

...except the top-level view controller, where the object is instantiated.

There is also a scenario where it is passed "through" a nested view controller, just for the sake of getting it to a more deeply nested view controller that utilizes it.

I know that singletons are generally frowned upon and go against OOP principles. I want the code to be easily maintainable. Am I taking the right approach or would a singleton do the trick without compromising code quality?

I would avoid the Singleton at all costs. Your approach encourages loose-coupling and allows you to increase your testability by mocking out the object (if you converted it from your concrete implementation). It generally adds more code but you should have better testability in your application. That allows you to use an IoC container and utilize Dependency Injection. There are many great articles and posts on the web and here on StackOverflow about such topics.

Perhaps your singleton might look like this:

public class MyViewController : UIViewController
{
    public MyViewController ()
    {
    }

    public void Foo()
    {
        FaceBookSingleton.Instance.DoSomeAction();
        FaceBookSingleton.Instance.Something = 4;
    }
}

How do you do your testing around Foo() ? How would you know, sooner, if you introduced a breaking change? How do you know what your dependency graph looks like? It's harder to test code like this. Don't count on people browsing your code base to try and figure out if they broke something. Help them out and yourself out by writing code that can be tested.

Now maybe look at something as such:

public interface ISocialMediaWidget
{
    ISocialMediaWidgetResponse DoSomeUnitOfWork();
}


public class ConcreteSocialMediaWidgetService
{
    protected readonly ISocialMediaWidget socialMediaWidget;

    public ConcreteSocialMediaWidgetService(ISocialMediaWidget widget)
    {
        this.socialMediaWidget = widget;
    }

    public ISocialMediaWidgetResponse Foo()
    {
        return socialMediaWidget.DoUnitOfWork();
    }
}

Writing tests around the aforementioned is much easier. You can also mock out the response from each interface to create all kinds of tests.

public void SocialMediaWidgetTest()
{   //pseudo code
    var testService = new MockObject(ConcreteSocialMediaWidgetService(MockObject_of_ISocialMediaWidget));
    Assert.Equals(someImplementation_of_ISocialMediaWidgetResponse, testService.Foo());
}

Firstly, singletons are largely just an alternative syntax for other perfectly acceptable OO strategies, like "factories" and memoization.

It's a question of syntax and what each syntax implies in your organization. If you do this, is it implied in your organization that some work might be done to product MyClass.Current ?

public class MyClass
{
  public static MyClass Current
  {
    get
    {
      if (SomeSortOfCache['MyClass.Current'] == null) {
        // do something to get populate it.
      }
      return SomeSortOfCache['MyClass.Current'];
    }
  }
}

Or, would your organization prefer something like this:

public class MyClass
{
  public static MyClass GetCurrent()
  {
    if (SomeSortOfCache['MyClass.Current'] == null) {
      // do something to get populate it.
    }
    return SomeSortOfCache['MyClass.Current'];
  }
}

Or, if you want to think of it as a factory, call the method BuildMyClass() or CreateMyClass() . Under the hood, the mechanisms are largely the same. It primarily a question of assumptions your organization makes about each syntax + naming convention.

Secondly, you've established that you only want or need to allow one instance of to exist. So, I'd suggest using a pattern that facilitates this gracefully, with the least amount of code.

In this case, a singleton would seem to be a better solution as you would eliminate a lot of repetitive code, and increase flexibility for changes as you quickly build out your application.

A singleton could also act as an intermediary to the Facebook object, making it simpler for various parts of your application to use.

Any resource that is limited in nature is a good candidate for accessing through a singleton.

我更喜欢使用单例方法,因为您只需要一个实例。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM