10

For example:

var duckBehaviors = new Duckbehavior();
duckBehaviors.quackBehavior = new Quack();
duckBehaviors.flyBehavior = new FlyWithWings();
Duck mallardDuck = new Duck(DuckTypes.MallardDuck, duckBehaviors)

As the Duck class contains all the behaviors(abstract), creating a new class MallardDuck (which extends Duck) does not seem to be required.

Reference: Head First Design Pattern, Chapter 1.

  • What is the types of Duckbehavior.quackBehavior and other fields' in your code? – max630 Jun 8 at 15:27
  • There is no dependency injection in your example. – David Conrad Jun 8 at 22:33
  • 11
    Inheritance is awesome when your a junior to mid level developer because there's a long history of refactoring tricks and design patterns around it. But most experienced developers I've talked to prefer really shallow inheritance hierarchies based on composition whenever possible. Inheritance can cause more tight coupling than necessary and can make changes difficult. – Mark Rogers Jun 8 at 23:46
  • 5
    @DavidConrad: The OP is not doing the new-ing up within the class. DI/IoC is about injecting dependencies, not about containers or about never using "new"; that's an entirely orthogonal concern. Besides, you always have to change the code somewhere -be it the composition root or some config file. The control is inverted here within the Duck type, as the thing that controls the creation of the dependencies is not the Duck ctor, but some outside context; this being a toy example given for clarity, it is perfectly fine that the outside context is represented by just the calling code. – Filip Milovanović Jun 10 at 3:23
21

Sure, but we call that composition and delegation. The Strategy Pattern and Dependency Injection might seem structurally similar but their intents are different.

The Strategy Pattern allows runtime modification of behavior under the same interface. I could tell a mallard duck to fly and watch it fly-with-wings. Then swap it out for a jet pilot duck and watch it fly with Delta airlines. Doing that while the program is running is a Strategy Pattern thing.

Dependency Injection is a technique to avoid hard coding dependencies so they can change independently without requiring clients to be modified when they change. Clients simply express their needs without knowing how they will be met. Thus how they are met is decided elsewhere (typically in main). You don't need two ducks to make use of this technique. Just something that uses a duck without knowing or caring which duck. Something that doesn't build the duck or go looking for it but is perfectly happy to use whatever duck you hand it.

If I have a concrete duck class I can have it implement it's fly behavior. I could even have it switch behaviors from fly-with-wings to fly-with-Delta based on a state variable. That variable could be a boolean, an int, or it could be a FlyBehavior that has a fly method that does whatever flying style without me having to test it with an if. Now I can change flying styles without changing duck types. Now Mallards can become pilots. This is composition and delegation. The duck is composed of a FlyBehavior and it can delegate flying requests to it. You can replace all your duck behaviors at once this way or hold something for each behavior or any combination in between.

This gives you all the same powers that inheritance has except one. Inheritance lets you express what Duck methods you're overriding in the Duck subtypes. Composition and delegation requires the Duck to explicitly delegate to subtypes from the start. This is far more flexible but it involves more keyboard typing and Duck has to know it's happening.

However, many people believe that inheritance has to be explicitly designed for from the beginning. And that if it hasn't been, that you should mark your classes as sealed/final to disallow inheritance. If you take that view then inheritance really has no advantage over composition and delegation. Because then either way you have to either design for extensibility from the start or be willing to tear things down later.

Tearing things down is actually a popular option. Just be aware that there are cases where it's a problem. If you've independently deployed libraries or modules of code that you don't intend to update with the next release you can end up stuck dealing with versions of classes that know nothing about what you're up to now.

While being willing to tear things down later can free you from over designing there is something very powerful about being able to design something that uses a duck without having to know what the duck will actually do when used. That not knowing is powerful stuff. It lets you stop thinking about ducks for awhile and think about the rest of your code.

"Can we" and "should we" are different questions. Favor Composition over Inheritance doesn't say never use inheritance. There are still cases where inheritance makes the most sense. I'll show you my favorite example:

public class LoginFailure : System.ApplicationException {}

Inheritance lets you create exceptions with more specific, descriptive names in only one line.

Try doing that with composition and you'll get a mess. Also, there is no risk of the inheritance yo-yo problem because there is no data or methods here to reuse and encourage inheritance chaining. All this adds is a good name. Never underestimate the value of a good name.

  • 1
    "Never underestimate the value of a good name". Emperor's new clothes time: LoginException is not a good name. It's classic "smurf naming" and, if I take away Exception, all I have is Login, it it tells me nothing of what went wrong. – David Arno Jun 10 at 9:34
  • Sadly we are stuck with the ridiculous convention of putting Exception on the end of every exception class, but please don't confuse "stuck with it" with "good". – David Arno Jun 10 at 9:36
  • @DavidArno If you can suggest a better name I'm all ears. Here we have the benefit of not being trapped in the conventions of an existing code base. If you had the power to change the world with a snap of your fingers what would you name it? – candied_orange Jun 10 at 10:48
  • I'd name them, StackOverflow, OutOfMemory, NullReferenceAccess, LoginFailure etc. Basically, take "Exception" off the name. And, if required, fix them so that it describes what went wrong. – David Arno Jun 11 at 8:43
  • @DavidArno by your command. – candied_orange Jun 13 at 1:37
7

You can replace almost any methodology with any other methodology and still produce working software. Yet some are a better fit to a particular problem than others.

It depends on a lot of things which one is preferable. Prior art in the application, experience in the team, expected future developments, personal preference and how hard it will likely be for a newcomer to get his head around it, to name a few.

As you get more experienced and struggled more often with other people's creations, you will likely put more emphasis on the last contemplation.

Inheritance is still a valid and strong modeling tool that is not necessarily always the most flexible but it offers strong guidance to new folks who may be grateful for the clear mapping to the problem domain.

-1

Inheritance is not as important as was once thought. It is still important, and removing it would be a bad mistake.

An extreme example is Objective-C where everything is a subclass of NSObject (the compiler actually doesn't allow you to declare a class that doesn't have a baseclass, so everything that isn't built into the compiler must be subclass of something built into the compiler). There is a lot of useful stuff built into NSObject that you wouldn't have to miss out on.

Another interesting example is UIView, the basic "view" class in UIKit for iOS development. This is a class that is on one hand a bit like an abstract class declaring functionality that subclasses are supposed to fill out, but it is also useful on its own. It has subclasses supplied by UIKit, which are often used as is. There is composition by developer installing subviews in a view. And there are often developer-defined subclasses, which often use composition. There is no strict single rule or even rules, you use whatever fits your requirements best.

  • Your "extreme example" is roughly how most modern OO languages function: Python subclasses type, every non-primitive in Java inherits from Object, everything in JavaScript has a prototype ending with Object, etc. – Delioth Jul 1 at 16:57
-1

[I'll hazard a cheeky answer to the titular question.]

Can we completely replace inheritance using strategy pattern and dependency injection?

Yes... except the strategy pattern itself uses inheritance. The strategy pattern works on interface inheritance. Replacing inheritance with composition+strategy moves inheritance to a different place. Nonetheless, such replacement often is worth doing, because it allows to tease apart hierarchies.

  • 2
    "The strategy pattern works on interface inheritance". Remember, the strategy pattern is a design pattern; not an implementation pattern. So it can be implemented using interfaces, but it can equally be implemented using eg a hash/dictionary of functions. – David Arno Jun 10 at 9:42
  • 3
    Interface inheritance is not at all inheritance, it's just a kinda contract or classifier. You can use delegates also for strategy pattern (I prefer using them). – Deepak Mishra Jun 11 at 3:06
  • Plus one, dude: ... works on interface inheritance, kudos on proper use of the general term "interface." I think poor or incompetent class design is the basic reason this question gets raised. To explain why/how would take a book; the devil is in the details. I've worked w/ inheritance designs that were a joy to behold and at the same time deep inheritance that was hell. I've seen craptastic interface design fixed with inheritance. The hidden problem here is inconsistent implementation morphing dependent behavior. P,S. inheritance & interface are not mutually exclusive, – radarbob Jun 19 at 0:00
  • @DavidArno comment: This comment would be fine if attached to the OP question. The OP question is technically mis-stated but we still get it. The issue is not this particular answer. – radarbob Jun 19 at 0:13
  • @DeepakMishra comment:. An "interface" is all public members of a class. Unfortunately "interface" meaning is overloaded. We must be careful to distinguish the general meaning with a programming language's keyword interface – radarbob Jun 19 at 0:20
-2

No. If a mallard duck requires different parameters to instantiate than some other type of duck, it'd be a nightmare to change. Also should you be able to instantiate a duck? It's more a mallard duck or Mandarin duck or whatever other kind of ducks you have.

Also I might want some logic around the types so a type hierarchy might be better.

Now if code reuse becomes problematic for some of the functionality, we could compose it by passing in the functions through the constructor.

Again, it really depends on your use case. If you just have a duck and a mallard duck, a class hierarchy is a much simpler solution.

But here is an example where you'd like to use the strategy pattern: If you have customer classes, and you want to pass in a billing strategy (interface) which could be happy hour billing strategy or regular billing strategy, you could pass it in the constructor. This way you don't have to make two different classes of customers and you don't need a hierarchy. You just have the one customer class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.