Skip to content
Advertisement

Using the “new” keyword in constructors

I’ve recently read that using the keyword “new” in a constructor is highly frowned upon, but I’m not sure I understand why? For example, how is:

JavaScript

Any different from:

JavaScript

???

Advertisement

Answer

This is really the theory behind dependency injection.

It’s not that using “new” is a bad idea, per se. Rather, by instantiating objects inside of your class your are creating hard dependencies which can never be changed or switched out without changing the class itself.

It also violates the paradigm of “coding to interface, not implementation”

Example:

JavaScript

Now, suppose one day you wanted to create an ATT, TMobile and Sprint phone? Surely they are all able to make calls, and can do so having just a phone number. Also, the phone class shouldn’t care who the carrier is, as it’s job is to facilitate entering a number – not to actually make a network connection, right?

So, that being said, we shouldn’t have to create a new SprintPhone class that can instantiate another Sprint network object, right? Right.

So what’s the better way?

JavaScript

Well now, you can just say: $phone = new Phone(new Sprint()) or $phone = new Phone(new Verizon())

Also notice that our call to distinctiveRing is gone. Why? Well, because we don’t know that any object implementing NetworkInterface will necessarily support a distinctive ring. But this is good because now our Phone can support ANY Network with no code changes.

If you want support for distinctive ring, you can always create a new interface that supports the distinctiveRing method. In your Phone object, you can check if your Network implements DistinctiveRingerInterface and, if so, make your distinctive ring. But you’re no longer tied to a specific network with this approach. Better yet, you were forced to do this because you took the right approach from the start.

And, any other network which can feasibly be created later down the road. More importantly, your class no longer has to care about what kind of Network object it’s given. It knows, (because it received an object implementing NetworkInterface), that the Network object is able to make a call with a $number.

This also tends to lead to much better code, with a better separation of concerns.

And finally: testing.

With the first example, if you tried to test your Phone object, it was going to make a call on the Verizon network. Sucks to be the person getting called all day because you’re running unit tests, right? Right.

Well, simply create a TestNetwork class that implements NetworkInterface, and pass that to your phone object. Your TestNetwork class can do anything you want inside of it’s call method – or do nothing.

Furthermore, you can just create a mock object using PHPUnit, and ensure that the call method on your TestNetwork actually gets called. You couldn’t do this before because the Network was being instantiated inside of your Phone.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement