Using mixins to share functionality

In the previous section we defined subclasses of SC.Object that inherit functionality from their parent classes. However, inheritance is too rigid for sharing code among classes that may not directly inherit from a shared parent.

For instance, in a previous example we defined a MyApp.Vehicle class and a MyApp.Car subclass of it. The MyApp.Car subclass added a topSpeed property supposedly unique to cars, but of course, topSpeed is not unique to cars. What if we had MyApp.Truck, MyApp.Boat, MyApp.Plane, MyApp.Helicopter, and other vehicle types? Some of these types will share common traits, such as top speed, but not all traits will be common to all vehicles, such as maximum altitude. How then would we subclass them to reduce redundancy?

While we could try to create hierarchies such as MyApp.Vehicle | MyApp.GroundVehicle | MyApp.Car | MyApp.Racing, this would likely end up being both too complex to manage and still not flexible enough for all cases. What about racing trucks, boats, and planes?

Obviously, inheritance is a nice tool for dividing classes into broad channels, but shouldn't be used too granularly. Instead, this type of situation calls for using a mixin that can be applied across multiple classes regardless of their hierarchy. Mixins are very easy to use in SproutCore; they are just regular JavaScript objects. Let's look at how to define and use them.

For example, to create a Raceable mixin containing the traits common to all racing vehicles, we simply define a Raceable JavaScript object:

 MyApp.Raceable = {
  
  /**  The total number of races.   */
  numRaces: 0,

  /** The results of each race.   */
  results: null

  /** @private Further initialize the object using this mixin when 
it is created. */
  initMixin: function () {
    // Initialize the results hash so that the JS object is unique 
to each instance.
    this.results = {};
  },

  /** @private Further clean up the object using this mixin when 
it is destroyed. */
  destroyMixin: function () {
    // Any special clean up required?  Not likely, but this 
function can do it.
  }

};

As you can see, there are two special functions that mixins can provide: initMixin and destroyMixin. These functions will be run when the object using the mixin is created or destroyed respectively.

You do not call sc_super() in initMixin or destroyMixin.

To apply a mixin to your classes or instances, simply add it as an argument when calling extend or create. This is illustrated in the following code:

// Include the Raceable mixin in all instances of a class.
MyApp.Car = MyApp.Vehicle.extend(MyApp.Raceable);
MyApp.Plane = MyApp.Vehicle.extend(MyApp.Raceable);

// Include the Raceable mixin in certain instances only.
var racingCar = MyApp.Car.create(MyApp.Raceable);

Since you can pass multiple arguments to create and extend, you can include several mixins along with your own custom hashes. For example:

// Create a dog instance that has properties of a show pet and a 
pedigreed pet.
var myDog = PetsApp.Dog(
    { color: 'black', breed: 'Boston Terrier' }, 
    PetsApp.Showable,      // Mixin
    PetsApp.Pedigreeable  // Mixin
  );

Note

You may wonder about multiple definitions of initMixin and destroyMixin overriding one another. This is not the case because both of these methods are what are called concatenated properties. Concatenated properties aren't overridden in subclasses, but appended to an array so that each may be applied.

The last thing to know about mixins is that SproutCore includes several prebuilt mixins that you can use to quickly add functionality to your classes. Some that may be of interest to you and that you should research on your own are SC.Freezable, SC.Copyable, and SC.Comparable. For now, it's enough that you are able to recognize the role of a mixin and know how to create and use them.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.245.233