14

This is something I've been mulling over while creating an AngularJS app. When I first learned about AngularJS factories, I thought one clever usage of them would be to create and return a constructor function rather than a plain object, i.e. something like:

app.factory("Foo", function() {
  function Foo(bar, baz) {
    this.bar = bar;
    this.baz = baz;
    ...
  }

  Foo.prototype = {
    constructor: Foo,
    method1: function() { ... },
    method2: function() { ... },
    ...,
    methodn: function() { ... },
  };

  return Foo;
});

Then, you could inject the function into your controllers and call it with new. I found this aesthetically pleasing and OOP-y, but now I'm starting to think that it's actually an anti-pattern. The problem is that it works fine for when you're working within AngularJS-aware contexts, but once you want to, for instance, call the constructor from the console, use it in a Web Worker, or reuse the code in a non-AngularJS app, you start having to work around AngularJS rather than with it. I began to wonder if this approach was misguided insofar as functions in javascript already seem to be "singletons" and don't seem to need any help being instantiated.

Am I misusing AngularJS factories? Would I be better served with constructor functions exposed to the global scope? More generally, are there specific factors which promote the usage of AngularJS factories/services/providers over global objects or vice versa?

brainkim
  • 902
  • 3
  • 11
  • 20
  • 1
    Instead of short-circuiting the value of dependency resolution provided by a Dependency Injection container, I'd suggest looking at the decorator pattern support OOTB by $provide.decorator(...) in Angular docs. Exposing a prototype isn't 'evil' but when you call 'new' on a component that has dependencies which _you_ are resolving, I am not sure what you gain except, perhaps, configurable prototypes based on a context. If that is what you are after, then you can use $inject.get('myWhatever') to turn it into Service Locator. – SonOfNun Aug 06 '13 at 07:08
  • 2
    It's not a good idea. The idea of a factory is to provide a value without worrying on how it's constructed. [This answer gives some good explanation on how to use factories, services and providers](http://stackoverflow.com/questions/15666048/angular-js-service-vs-provide-vs-factory). – Bart Aug 06 '13 at 07:12

2 Answers2

6

Yes!

Factories Syntax: module.factory( 'factoryName', function ); Result: When declaring factoryName as an injectable argument you will be provided the value that is returned by invoking the function reference passed to module.factory. Usage: Could be useful for returning a 'class' function that can then be new'ed to create instances.

Source: https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/HuZsOsMvKv4J

The above link is also used as the source to Bart's comment: AngularJS: Service vs provider vs factory

Community
  • 1
  • 1
Al Johri
  • 1,729
  • 22
  • 23
0

Maybe this is a nice and convenient use in context of Angular and Javascript (which happens to allow mind boggling manipulations with constructors and object prototypes), but, in my opinion, it somewhat contradicts classical Factory pattern logic.

Factory is meant to construct new objects inside of it, applying some configuration, initialization and injecting dependencies into the newly created object, as specified in factory settings (if you have any).

For example, you can ask a factory to create a storage connection, and the factory creates a MySQL connection, SQLite connection or Redis connection - your controller doesn't really care, as long as the constructed object implements some interface (or use duck-typing in Javascript context - if it quacks like a duck, it is a duck).

But if you use new keyword after you have called a Factory working outside of the Factory, then it's as if you say the following:

"Hey, factory, give me a prototype (constructor) of some item and I will create the item myself."

So, in this case your factory is not a "classical factory" for creating new objects but some prototype factory that has one prototype to provide to all callers so they can themselves manufacture new objects.

When you have simple constructors without any arguments, you might be ok with that, but in the classical example (the storage connection) such use of factories doesn't make sense because then the caller of the factory has to do the job of the factory - inject configurations and dependencies into the newly created object.

JustAMartin
  • 13,165
  • 18
  • 99
  • 183