Fernando y Jorge, contribuidores de esta página, dieron este webinar en Software Gurú Campus.
Las diapositivas en Slide Share
public static void main(String[] args) {
double notANumber = Double.NaN;
System.out.println(notANumber == Double.NaN);
}
Si tenemos una objeto o1 de la clase A y un objeto o2 de la clase B entonces en un programa escrito en función de B podemos sustituir el objeto o1 por o2 si alterar la funcionalidad del sistema si A es un subtipo de B.
public class LiskovSustitution {
public static void main(String[] args) {
OtroItem o1 = new OtroItem();
Item o2 = new Item();
hacerAlgo(o1); Aquí podemos reemplazar o1 por o2 sin afectar la funcionalidad.
}
static void hacerAlgo(Item b){
b.update();
}
}
class OtroItem extends Item{
public void hacerOtraCosa(){
System.out.println("Hacer otra cosa");
}
}
class Item{
public void update(){
System.out.println("Item updated");
}
}
public class LiskovSustitution {
public static void main(String[] args) {
OtroItem o1 = new OtroItem();
Item o2 = new Item();
hacerAlgo(o1); Aquí podemos reemplazar o1 por o2.
}
static void hacerAlgo(Item b){
b.update();
}
}
class NoUpdatableItem extends Item{
public void update (){
throw UnsoportedOperation();
}
}
class Item{
public void update(){
System.out.println("Item updated");
}
}
public class LiskovSustitution {
public static void main(String[] args) {
OtroItem o1 = new OtroItem();
Item o2 = new Item();
hacerAlgo(o1); Aquí podemos reemplazar o1 por o2.
}
static void hacerAlgo(Item b){
if( ! b instanceof NoUpdatableItem)
b.update();
}
}
class NoUpdatableItem extends Item{
public void update (){
throw UnsoportedOperation();
}
}
class Item{
public void update(){
System.out.println("Item updated");
}
}
class Item{
String nombre;
public Item(final String nombre){
this.nombre=nombre;
}
}
class UpdatableItem extends Item{
public UpdatableItem(String nombre) {
super(nombre);
}
public void update(){
System.out.println("Update item");
}
}
class NoUpdatableItem extends Item{
public NoUpdatableItem(String nombre) {
super(nombre);
}
}
package gildedrose;
class GildedRose {
Item[] items;
public GildedRose(final Item[] items) {
this.items = items;
}
public void updateQuality() {
for (int i = 0; i < items.length; i++) {
if (!items[i].name.equals("Aged Brie")
&& !items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
if (items[i].quality > 0) {
if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
items[i].quality = items[i].quality - 1;
}
}
} else {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1;
if (items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
if (items[i].sellIn < 11) {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1;
}
}
if (items[i].sellIn < 6) {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1;
}
}
}
}
}
if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
items[i].sellIn = items[i].sellIn - 1;
}
if (items[i].sellIn < 0) {
if (!items[i].name.equals("Aged Brie")) {
if (!items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
if (items[i].quality > 0) {
if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
items[i].quality = items[i].quality - 1;
}
}
} else {
items[i].quality = items[i].quality - items[i].quality;
}
} else {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1;
}
}
}
}
}
}
Veamos el Sistema ya con los cambios: package gildedrose;
public class GildedRoseSystem {
private ItemUpgradeInstanceable factory;
public GildedRoseSystem() {
this(GildedRoseMainFactory.getItemUpgradableFactory());
}
public GildedRoseSystem(final ItemUpgradeInstanceable factory) {
this.factory = factory;
}
public void updateItem(final Item item) {
ItemUpgradeable upgratable = this.factory.getInstance(item);
upgratable.updateQuality(item);
upgratable.updateSellIn(item);
}
}
El sistema tiene como responsabilidad es actualizar de cada tipo de queso(item) su calidad y su fecha limite de venta, sin siquiera saber el detalle de como se actualiza cada propiedad de los tipos de quesos, ni que reglas de negocio aplican para cada propiedad y tipo de queso, su responsabilidad es clara, modular y encapsulada.package gildedrose;
public class NormalItemUpgradeable implements ItemUpgradeable {
private GildedRoseBusiness business;
public NormalItemUpgradeable() {
business = new GildedRoseBusiness();
}
@Override
public void updateQuality(final Item item) {
this.business.degreteQualityInOne(item);
if (item.sellIn <= 0) {
business.degreteQualityInOne(item);
}
}
@Override
public void updateSellIn(final Item item) {
this.business.degreteSellIn(item);
}
}
Los quesos normales saben que su calidad se degrada en uno y que si su fecha de venta limite ya paso se degrada al doble, ha reglas de negocio que se aplican a dicho degradado pero es una responsabilidad que no es propia del tipo de queso. Veamos otro tipo de queso:package gildedrose;
public class BackstageSpecialItemUpgradeable implements ItemUpgradeable {
private GildedRoseBusiness business;
public BackstageSpecialItemUpgradeable() {
business = new GildedRoseBusiness();
}
@Override
public void updateQuality(final Item item) {
business.incrementQualityInOne(item);
updateQualityInSpecialSellinTime(item);
}
@Override
public void updateSellIn(final Item item) {
business.degreteSellIn(item);
}
private void updateQualityInSpecialSellinTime(final Item item) {
if (item.sellIn < 11)
business.incrementQualityInOne(item);
if (item.sellIn < 6)
business.incrementQualityInOne(item);
if (item.sellIn <= 0)
item.quality = item.quality - item.quality;
}
}
Este queso a diferencia del normal aumenta su calidad con forme se acerca a su fecha limite de venta en uno, dos o tres dependiendo el rango de proximidad a dicha fecha y una ves que llega a la fecha la calidad es cero, a cada incremento se le aplica una regla de negocio que no es responsabilidad como tal de el queso.package gildedrose;
public class GildedRoseBusiness {
public void degreteSellIn(Item item) {
if (!item.name.equals("Sulfuras, Hand of Ragnaros")) {
item.sellIn = item.sellIn - 1;
}
}
public void incrementQualityInOne(Item item) {
if (item.quality < 50) {
item.quality = item.quality + 1;
}
}
public void degreteQualityInOne(Item item) {
if (item.quality > 0) {
item.quality = item.quality - 1;
}
}
}
Ven esta clase se encuentran todas las definiciones del negocio en cuanto al decremento e incremento de la calidad sin importar como las aplique cada item y al decremento de la fecha limite.class SistemaProductos{
.
.
.
public void updateQuality() {
for (int i = 0; i < products.length; i++) {
if (!products[i].name.equals("Increase")
&& !products[i].name.equals("KeepQuality")) {
if (products[i].quality > 0) {
products[i].quality = products[i].quality - 1;
}
} else {
if (products[i].quality < 50) {
if (products[i].name.equals("Increase")
&& !products[i].name.equals("KeepQuality")){
products[i].quality = products[i].quality + 1;
}
}
}
}
}
}
public interface QualityUpdater {
public void updateQuality(final Item item);
}
public class Producto {
public String name;
public int quality;
public QualityUpdater qualityUpdater;
public Producto(final String name, final int quality) {
this.name = name;
this.quality = quality;
}
}
public class SustemaProductos{
.
.
.
public void updateQuality() {
for (Producto product : products) {
product.qualityUpdater.updateQuality(product);
}
}
}
public class IncrementProduct implements QualityUpdater {
private static final int MAX_QUALITY_PRODUCT = 50;
@Override
public void updateQuality(final Producto producto) {
if (hasQualityToIncrease(producto)) {
increaseQuality(producto);
}
}
private static boolean hasQualityToIncrease(final Producto producto) {
return producto.quality < MAX_QUALITY_PRODUCT;
}
private static void increaseQuality(final Producto producto) {
producto.quality ++;
}
}
public class DecrementProduct implements QualityUpdater {
private static final int MIN_QUALITY_PRODUCT = 0;
@Override
public void updateQuality(final Producto producto) {
if (hasQualityToDecrease(producto)) {
decreaseQuality(producto);
}
}
private static boolean hasQualityToDecrease(final Producto producto) {
return producto.quality > MIN_QUALITY_PRODUCT;
}
private static void decreaseQuality(final Producto producto) {
producto.quality --;
}
}
public class Producto {
.
.
.
public boolean isUpdatableQuality() {
return qualityUpdater != null;
}
}
public class SistemaProductos{
.
.
.
public void updateQuality() {
for (Producto product : products) {
if (product.isUpdatableQuality()) {
product.qualityUpdater.updateQuality(product);
}
}
}
}
product.qualityUpdater.updateQuality(product);
The interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use. ISP splits interfaces which are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them...
...
public interface ItemUpdater {
void updateSellIn(Item item);
void updateQuality(Item item);
}
public class RegularItemUpdater implements ItemUpdater {
@Override
public void updateSellIn(final Item item) {
item.setSellIn(item.getSellIn() - 1);
}
@Override
public void updateQuality(final Item item) {
item.setQuality(item.getQuality()-1);
}
}
public interface SellInUpdater {
void updateSellIn(Item item);
}
public interface QualityUpdater {
void updateQuality(Item item);
}
public class ItemUpdater {
private QualityUpdater qualityUpdater;
private SellInUpdater sellInUpdater;
public ItemUpdater(SellInUpdater sellInUpdater, QualityUpdater qualityUpdater) {
this.sellInUpdater = sellInUpdater;
this.qualityUpdater = qualityUpdater;
}
public void updateItem(Item item) {
this.sellInUpdater.updateSellIn(item);
this.qualityUpdater.updateQuality(item);
}
}
public class Item {
private String name;
private int sellIn;
private int quality;
private QualityUpdater qualityUpdater;
private SellInUpdater sellInUpdater;
public Item(String name, int sellIn, int quality) {
this.name = name;
this.sellIn = sellIn;
this.quality = quality;
selectUpdaters();
}
private void selectUpdaters() {
this.sellInUpdater = DispacherUpdaters.getSellInUpdater(name);
this.qualityUpdater = DispacherUpdaters.getQualityUpdater(name);
}
public String getters() {...}
public void setters() {...}
public void update(){
updateSellIn();
updateQuality();
}
private void updateQuality() {
qualityUpdater.updateQuality(this);
}
private void updateSellIn(){
sellInUpdater.updateSellIn(this);
}
}
public class Item {
public String name;
public int sellIn;
public int quality;
public Item(String name, int sellIn, int quality) {
this.name = name;
this.sellIn = sellIn;
this.quality = quality;
}
public String getters() {...}
public void setters() {...}
}
public class ItemUpdateable extends Item implements Updateable{
private QualityUpdater qualityUpdater;
private SellInUpdater sellInUpdater;
public ItemUpdateable(String name, int sellIn, int quality) {
super(name, sellIn, quality);
}
public void setQualityUpdater(QualityUpdater qualityUpdater) {
this.qualityUpdater = qualityUpdater;
}
public void setSellInUpdater(SellInUpdater sellInUpdater) {
this.sellInUpdater = sellInUpdater;
}
@Override
public void update() {
sellInUpdater.updateSellIn(this);
qualityUpdater.updateQuality(this);
}
}