diseño orientado a objetos
Mientras más temprana sea la etapa en donde se genere un defecto, más cuesta corregir el mismo
Acoplamiento: grado de dependencia que tienen dos unidades de software
Cohesión: forma en la que agrupamos unidades de software en una unidad mayor
Abstracción: Aislar un elemento de su contexto o del resto de los elementos que lo acompañan.
Extensibilidad: Capacidad de un programa o clase por la cual permite extender funcionalidades con el menor impacto posible.
Law of Demeter
“Only talk to your immediate friends”
int price = customer.getOrder().getPrice();
int price = customer.getOrderPrice();
Extensibilidad
Incorporar nuevo funcionamiento
Escalabilidad
Agregar capacidad
Herencia
Composición
Polimorfismo
Single Responsibility Principle
Open Close Principle
Liskov's Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
Una clase/método sólo debe tener una razón para cambiar (responsabilidad)
class Modem {
void send(message) {
// 1. dial-up
// 2. send message
// 3. hangup
}
string recv() {
// receiving new message
// 1. dial up
// 2. receive message
// 3. hangup
}
}
class Modem {
void send(message) {
dial();
// sending message
hangup();
}
string recv() {
dial();
// receiving new message
hangup();
}
void hangup() {
// do stuf...
}
void dial(number) {
// dialing number..
}
}
Una clase debe permitir ser extendida (Open for Extensions), sin necesitar ser modificada (Close for modifications)
class GraphicEditor {
void DrawRectangle() {
// ...
}
void DrawCircle() {
// ...
}
}
editor = new GraphicEditor();
if (type == 1)
editor.DrawRectangle();
if (type == 2)
editor.DrawCircle();
class GraphicEditor {
void DrawFigure(Figure f)
f.Draw();
}
}
class Figure {
void Draw();
}
class Rectangle extends Figure {
void Draw() {
// draw
}
}
Una clase derivada debe poder ser reemplazada en su totalidad por una clase base
public interface IDuck {
void Swim();
}
public class Duck : IDuck {
public void Swim() {
//do something to swim
}
}
public class ElectricDuck : IDuck {
public void Swim() {
if (!IsTurnedOn)
this.TurnOn();
//swim logic
}
public void TurnOn() {
this.turnOn = True;
}
}
void MakeDuckSwim(IDuck duck) {
duck.Swim();
}
public interface IDuck {
void Swim();
}
public class Duck : IDuck {
public void Swim() {
//do something to swim
}
}
public class ElectricDuck : IDuck {
public void Swim() {
if (!IsTurnedOn)
return;
}
public void TurnOn() {
this.turnOn = True;
}
}
void MakeDuckSwim(IDuck duck) {
if (duck is ElectricDuck)
((ElectricDuck)duck).TurnOn();
duck.Swim();
}
No se debe forzar a una clase a depender de interfaces que no utiliza
interface IWorker {
public void work();
public void eat();
}
class Worker implements IWorker{
public void work() {
// working
}
public void eat() {
// eating in launch break
}
}
class RobotWorker implements IWorker {
public void work() {
// working
}
public void eat() {
// i dont have to eat
}
}
interface IWorkerable {
public void work();
}
interface IFeedable {
public void eat();
}
class Worker implements IWorkerable, IFeedable {
public void work() {
// working
}
public void eat() {
// eating in launch break
}
}
class RobotWorker implements IWorker {
public void work() {
// working
}
}
Las abstracciones no deben depender de los detalles, los detalles deben depender de las abstracciones.
class Worker {
public void work() {
// ....working
}
}
class Manager {
Worker worker;
public void setWorker(Worker w) {
worker = w;
}
public void manage() {
worker.work();
}
}
class SuperWorker {
public void work() {
//.... working much more
}
}
interface IWorker {
public void work();
}
class Worker implements IWorker {
public void work() {
// ....working
}
}
class SuperWorker implements IWorker {
public void work() {
//.... working much more
}
}
class Manager {
IWorker worker;
public void setWorker(IWorker w) {
worker = w;
}
public void manage() {
worker.work();
}
}
Ver: Articulo relacionado (pag 123)
No pretenden ser recetas mágicas
ni eliminar la creatividad.
Para realizar un buen diseño basta con entender el modelo de negocio
"One instance to rule them all"
Ejemplos