0% found this document useful (0 votes)
53 views

The Mixin Pattern: Sub-Classing Is A Term That Refers To Inheriting Properties For A New Object From A Base

The document discusses the Mixin pattern in programming. Mixins allow objects to inherit functionality from other objects with minimal complexity. This is done by extending object prototypes to include common behaviors, like moving functions. The document provides an example of augmenting a Car constructor with a Mixin to inherit drive methods like driveForward without duplicating code. While Mixins decrease duplication, some argue they can pollute prototypes and make function origins uncertain in large systems.

Uploaded by

Minal Patil
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
53 views

The Mixin Pattern: Sub-Classing Is A Term That Refers To Inheriting Properties For A New Object From A Base

The document discusses the Mixin pattern in programming. Mixins allow objects to inherit functionality from other objects with minimal complexity. This is done by extending object prototypes to include common behaviors, like moving functions. The document provides an example of augmenting a Car constructor with a Mixin to inherit drive methods like driveForward without duplicating code. While Mixins decrease duplication, some argue they can pollute prototypes and make function origins uncertain in large systems.

Uploaded by

Minal Patil
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 6

The Mixin Pattern

In traditional programming languages such as C++ and Lisp, Mixins are classes
which offer functionality that can be easily inherited by a sub-class or group of sub-
classes for the purpose of function re-use.

Sub-classing
For developers unfamiliar with sub-classing, we will go through a brief beginners
primer on them before diving into Mixins and Decorators further.

Sub-classing is a term that refers to inheriting properties for a new object from a base
or superclass object. In traditional object-oriented programming, a class B is able to
extend another class A . Here we consider A a superclass and B a subclass of A . As
such, all instances of B inherit the methods from A . B is however still able to define
its own methods, including those that override methods originally defined by A .
Should B need to invoke a method in A that has been overridden, we refer to this as
method chaining. Should B need to invoke the constructor A (the superclass), we
call this constructor chaining.
In order to demonstrate sub-classing, we first need a base object that can have new
instances of itself created. let's model this around the concept of a person.

?
1 var Person = function( firstName, lastName ){
2
3 this.firstName = firstName;
4 this.lastName = lastName;
5 this.gender = "male";
6
};
7
Next, we'll want to specify a new class (object) that's a subclass of the
existing Person object. Let us imagine we want to add distinct properties to
distinguish a Person from a Superhero whilst inheriting the properties of
the Person "superclass". As superheroes share many common traits with normal
people (e.g. name, gender), this should hopefully illustrate how sub-classing works
adequately.
?
1 // a new instance of Person can then easily be created as follows:
2 var clark = new Person( "Clark", "Kent" );
3
// Define a subclass constructor for for "Superhero":
4
var Superhero = function( firstName, lastName, powers ){
5
6 // Invoke the superclass constructor on the new object
7 // then use .call() to invoke the constructor as a method of
8 // the object to be initialized.
9
10 Person.call( this, firstName, lastName );
11
// Finally, store their powers, a new array of traits not found in a normal "P
12 this.powers = powers;
13 };
14
15 Superhero.prototype = Object.create( Person.prototype );
16 var superman = new Superhero( "Clark", "Kent", ["flight","heat-vision"] );
console.log( superman );
17
18 // Outputs Person attributes as well as powers
19
20
21
The Superhero constructor creates an object which descends from Person . Objects of
this type have attributes of the objects that are above it in the chain and if we had set
default values in the Person object, Superhero is capable of overriding any inherited
values with values specific to it's object.

Mixins
In JavaScript, we can look at inheriting from Mixins as a means of collecting
functionality through extension. Each new object we define has a prototype from
which it can inherit further properties. Prototypes can inherit from other object
prototypes but, even more importantly, can define properties for any number of
object instances. We can leverage this fact to promote function re-use.

Mixins allow objects to borrow (or inherit) functionality from them with a minimal
amount of complexity. As the pattern works well with JavaScripts object prototypes,
it gives us a fairly flexible way to share functionality from not just one Mixin, but
effectively many through multiple inheritance.

They can be viewed as objects with attributes and methods that can be easily shared
across a number of other object prototypes. Imagine that we define a Mixin
containing utility functions in a standard object literal as follows:

?
1 var myMixins = {
2
3 moveUp: function(){
console.log( "move up" );
4 },
5
6 moveDown: function(){
7 console.log( "move down" );
},
8
9 stop: function(){
10 console.log( "stop! in the name of love!" );
11 }
12
13 };
14
15
We can then easily extend the prototype of existing constructor functions to include
this behavior using a helper such as the Underscore.js _.extend() method:
?
1
2
3 // A skeleton carAnimator constructor
4 function CarAnimator(){
5 this.moveLeft = function(){
console.log( "move left" );
6 };
7 }
8
9 // A skeleton personAnimator constructor
10 function PersonAnimator(){
this.moveRandomly = function(){ /*..*/ };
11 }
12
13 // Extend both constructors with our Mixin
14 _.extend( CarAnimator.prototype, myMixins );
_.extend( PersonAnimator.prototype, myMixins );
15
16 // Create a new instance of carAnimator
17 var myAnimator = new CarAnimator();
18 myAnimator.moveLeft();
19 myAnimator.moveDown();
myAnimator.stop();
20
21 // Outputs:
22 // move left
23 // move down
// stop! in the name of love!
24
25
26
As we can see, this allows us to easily "mix" in common behaviour into object
constructors fairly trivially.

In the next example, we have two constructors: a Car and a Mixin. What we're going
to do is augment (another way of saying extend) the Car so that it can inherit specific
methods defined in the Mixin, namely driveForward() and driveBackward() . This time we
won't be using Underscore.js.
Instead, this example will demonstrate how to augment a constructor to include
functionality without the need to duplicate this process for every constructor
function we may have.

?
// Define a simple Car constructor
1 var Car = function ( settings ) {
2
3 this.model = settings.model || "no model provided";
this.color = settings.color || "no colour provided";
4
5 };
6
7 // Mixin
8 var Mixin = function () {};
9
10 Mixin.prototype = {
11
driveForward: function () {
12 console.log( "drive forward" );
13 },
14
15 driveBackward: function () {
console.log( "drive backward" );
16 },
17
18 driveSideways: function () {
19 console.log( "drive sideways" );
}
20
21 };
22
23
24 // Extend an existing object with a method from another
25 function augment( receivingClass, givingClass ) {
26
27 // only provide certain methods
if ( arguments[2] ) {
28 for ( var i = 2, len = arguments.length; i < len; i++ ) {
29 receivingClass.prototype[arguments[i]] = givingClass.prototype[argumen
30 }
}
31 // provide all methods
32 else {
33 for ( var methodName in givingClass.prototype ) {
34
35 // check to make sure the receiving class doesn't
// have a method of the same name as the one currently
36 // being processed
37 if ( !Object.hasOwnProperty.call(receivingClass.prototype, methodName)
38 receivingClass.prototype[methodName] = givingClass.prototype[metho
}
39
40 // Alternatively (check prototype chain as well):
41 // if ( !receivingClass.prototype[methodName] ) {
42 // receivingClass.prototype[methodName] = givingClass.prototype[method
// }
43
}
44 }
45 }
46
47
48 // Augment the Car constructor to include "driveForward" and "driveBackward"
augment( Car, Mixin, "driveForward", "driveBackward" );
49
50 // Create a new Car
var myCar = new Car({
51 model: "Ford Escort",
52 color: "blue"
53 });
54
55 // Test to make sure we now have access to the methods
myCar.driveForward();
56 myCar.driveBackward();
57
58 // Outputs:
59 // drive forward
// drive backward
60
61 // We can also augment Car to include all functions from our mixin
62 // by not explicitly listing a selection of them
63 augment( Car, Mixin );
64
var mySportsCar = new Car({
65 model: "Porsche",
66 color: "red"
67 });
68
69 mySportsCar.driveSideways();
70
// Outputs:
71 // drive sideways
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
Advantages & Disadvantages
Mixins assist in decreasing functional repetition and increasing function re-use in a
system. Where an application is likely to require shared behaviour across object
instances, we can easily avoid any duplication by maintaining this shared
functionality in a Mixin and thus focusing on implementing only the functionality in
our system which is truly distinct.
That said, the downsides to Mixins are a little more debatable. Some developers feel
that injecting functionality into an object prototype is a bad idea as it leads to both
prototype pollution and a level of uncertainty regarding the origin of our functions.
In large systems this may well be the case.

I would argue that strong documentation can assist in minimizing the amount of
confusion regarding the source of mixed in functions, but as with every pattern, if
care is taken during implementation we should be okay.

You might also like