Mostrando entradas con la etiqueta OOP. Mostrar todas las entradas
Mostrando entradas con la etiqueta OOP. Mostrar todas las entradas

sábado, 7 de junio de 2014

Javascript OOP, Visual Method - Part II

Previous post: Javascript OOP, Visual Method




Refactoring to preserve Liskov's Substitution Principle.
   Note: Due "super" is a reserved word, "soper" is its replacement.




/* IShape -- abstract class */
function IShape(obj) {
  if(obj.area && obj.perimeter) return obj;
  else return undefined;
};

/* Circle constructor */
function circle(radius) {
  return IShape( {
    "area": function() {
      return Math.PI * radius * radius;
    },
    "perimeter": function() {
      return 2 * Math.PI * radius;
    }
  });
};

/* Rectangle constructor */
function rectangle(length, width) {
  return IShape( {
    "area": function() { 
      return length * width;
    },
    "perimeter": function() {
      return (2 * length) + (2 * width);
    }
  });
};

/* Triangle constructor */
function triangle(base, height) {
  return IShape( {
    "area": function() {
      return base * height;
    },
    "perimeter": function() {
      return undefined;
    }
  });
};

/* Square -- child class -- constructor */
function square(side) {
  return IShape( {
    "soper": rectangle(side, side),
    "area": function() {
      return this.soper.area();
    },
    "perimeter": function() {
      return this.soper.perimeter(side, side);
    }
  });
};

/* Shapes factory */
function shapesFactory(shapeId) {
  switch (shapeId.toLowerCase()) {
    case "circle":
      return circle;
    case "rectangle":
      return rectangle;
    case "triangle":
      return triangle;
    case "square":
      return square;
    default:
      return undefined;
  }
};

// TESTS
var shape1 = shapesFactory("circle")(1);

console.log("Circle(radius=1)."+
   " Area: " + shape1.area() +
   " Perimeter: " + shape1.perimeter());
// output:
// Circle(radius=1). Area: 3.141592653589793 Perimeter: 6.283185307179586 

var shape2 = shapesFactory("rectangle")(2,3);

console.log("Rectangle(length=2, width=3)."+
   " Area: " + shape2.area() +
   " Perimeter: " + shape2.perimeter());
// output:
// Rectangle(length=2, width=3). Area: 6 Perimeter: 10

var shape3 = shapesFactory("triangle")(2,3);

console.log("Triangle(base=2, height=3)."+
   " Area: " + shape3.area() +
   " Perimeter: " + shape3.perimeter());
// output:
// Triangle(base=2, height=3). Area: 6 Perimeter: undefined

var shape4 = shapesFactory("square")(1);

console.log("Square(radius=1)."+
   " Area: " + shape4.area() +
   " Perimeter: " + shape4.perimeter());
// output:
// Square(radius=1). Area: 1 Perimeter: 4

viernes, 6 de junio de 2014

Javascript OOP, Visual Method

Let's do this inheritance example with Javascript:



All objects must calculate area and perimeter through a common interface and must be generated through a factory.



/* IShape -- abstract class */
function IShape(area, perimeter) {
  return { "area":area, "perimeter":perimeter };
};

/* Circle constructor */
function circle() {
  var area = function(radius) {
    return Math.PI * radius * radius;
  };
  var perimeter = function(radius) {
    return 2 * Math.PI * radius;
  };
  return IShape(area, perimeter);
};

/* Rectangle constructor */
function rectangle() {
  var area = function(length, width) {
    return length * width;
  };
  var perimeter = function(length, width) {
    return (2 * length) + (2 * width);
  };
  return IShape(area, perimeter);
};

/* Triangle constructor */
function triangle() {
  var area = function(base, height) {
    return base * height;
  };
  var perimeter = function() {
    return undefined;
  };
  return IShape(area, perimeter);
};

/* Square -- child class -- constructor */
function square() {
  var extendedObject = rectangle();
  var area = function(side) {
    return extendedObject.area(side, side);
  };
  var perimeter = function(side) {
    return extendedObject.perimeter(side, side);
  };
  return IShape(area, perimeter);
};

/* Shapes factory */
function shapesFactory(shapeId) {
  switch (shapeId.toLowerCase()) {
    case "circle":
      return circle();
    case "rectangle":
      return rectangle();
    case "triangle":
      return triangle();
    case "square":
      return square();
    default:
      return undefined;
  }
};

// TESTS
var shape1 = shapesFactory("circle");

console.log("Circle(radius=1)."+
   " Area: " + shape1.area(1) +
   " Perimeter: " + shape1.perimeter(1));
// output:
// Circle(radius=1). Area: 3.141592653589793 Perimeter: 6.283185307179586 

var shape2 = shapesFactory("rectangle");

console.log("Rectangle(length=2, width=3)."+
   " Area: " + shape2.area(2,3) +
   " Perimeter: " + shape2.perimeter(2,3));
// output:
// Rectangle(length=2, width=3). Area: 6 Perimeter: 10

var shape3 = shapesFactory("triangle");

console.log("Triangle(base=2, height=3)."+
   " Area: " + shape3.area(2,3) +
   " Perimeter: " + shape3.perimeter(2,3));
// output:
// Triangle(base=2, height=3). Area: 6 Perimeter: undefined

var shape4 = shapesFactory("square");

console.log("Square(radius=1)."+
   " Area: " + shape4.area(1) +
   " Perimeter: " + shape4.perimeter(1));
// output:
// Square(radius=1). Area: 1 Perimeter: 4




Using JQuery the factory could be an object on another file:


/* Shapes factory */
jQuery.shapesFactory = function(shapeId) {

  /* IShape -- abstract class */
  function IShape(area, perimeter) {
    return { "area":area, "perimeter":perimeter };
  };

  /* Circle constructor */
  function circle() {
    var area = function(radius) {
      return Math.PI * radius * radius;
    };
    var perimeter = function(radius) {
      return 2 * Math.PI * radius;
    };
    return IShape(area, perimeter);
  };

  /* Rectangle constructor */
  function rectangle() {
    var area = function(length, width) {
      return length * width;
    };
    var perimeter = function(length, width) {
      return (2 * length) + (2 * width);
    };
    return IShape(area, perimeter);
  };

  /* Triangle constructor */
  function triangle() {
    var area = function(base, height) {
      return base * height;
    };
    var perimeter = function() {
      return undefined;
    };
    return IShape(area, perimeter);
  };

  /* Square -- child class -- constructor */
  function square() {
    var extendedObject = rectangle();
    var area = function(side) {
      return extendedObject.area(side, side);
    };
    var perimeter = function(side) {
      return extendedObject.perimeter(side, side);
    };
    return IShape(area, perimeter);
  };

  /* Shapes factory */
  switch (shapeId.toLowerCase()) {
    case "circle":
      return circle();
    case "rectangle":
      return rectangle();
    case "triangle":
      return triangle();
    case "square":
      return square();
    default:
      return undefined;
  }
};

// TESTS - Another file -
var shape1 = $.shapesFactory("circle");

console.log("Circle(radius=1)."+
   " Area: " + shape1.area(1) +
   " Perimeter: " + shape1.perimeter(1));
// output:
// Circle(radius=1). Area: 3.141592653589793 Perimeter: 6.283185307179586 

var shape2 = $.shapesFactory("rectangle");

console.log("Rectangle(length=2, width=3)."+
   " Area: " + shape2.area(2,3) +
   " Perimeter: " + shape2.perimeter(2,3));
// output:
// Rectangle(length=2, width=3). Area: 6 Perimeter: 10

var shape3 = $.shapesFactory("triangle");

console.log("Triangle(base=2, height=3)."+
   " Area: " + shape3.area(2,3) +
   " Perimeter: " + shape3.perimeter(2,3));
// output:
// Triangle(base=2, height=3). Area: 6 Perimeter: undefined

var shape4 = $.shapesFactory("square");

console.log("Square(radius=1)."+
   " Area: " + shape4.area(1) +
   " Perimeter: " + shape4.perimeter(1));
// output:
// Square(radius=1). Area: 1 Perimeter: 4



Part II: Managing to preserve Liskov's Substitution Principle (LSP)

jueves, 12 de agosto de 2010

Erlang: Mapping Objects Classes to Actors Model

You can "map" an object class to actor. Lets see a simple example:

public class myClass
{
   private string myProperty;

   public myClass(string argInit) {
      myProperty = argInit;
   }

   public myMethod(string arg1, int arg2) {
      //do something
      myProperty = arg1 + arg2.toString();
   }
}

The actor (process with Erlang) is:

myClass(myProperty) ->
   receive
      {myMethod, Arg1, Arg2 } ->
         myClass(Arg1 ++ Arg2)
   end.

And it's "constructor" is the spawn of process:

spawn( myClass, [argInit ]).

Thus, an object's method (OOP) is an actor's message. Like UML sequence diagrams.