Polymorphism refactoring

This commit is contained in:
tbuckinx 2023-11-23 22:28:59 +01:00
parent 3ad7c801f8
commit 3b32b9a6bf
9 changed files with 251 additions and 100 deletions

View File

@ -1,12 +1,18 @@
package com.gildedrose;
import static com.gildedrose.Inventory.BACKSTAGE_PASS;
import static com.gildedrose.Inventory.LEGENDARY;
import static com.gildedrose.service.InventoryHelper.*;
import com.gildedrose.domain.*;
import com.gildedrose.service.InventoryItem;
import static java.util.stream.IntStream.range;
import static java.util.stream.Stream.of;
class GildedRose {
private static final String AGED_BRIE = "Aged Brie";
private static final String LEGENDARY = "Sulfuras, Hand of Ragnaros";
private static final String CONJURED_ITEM = "Conjured Mana Cake";
private static final String BACKSTAGE_PASS = "Backstage passes to a TAFKAL80ETC concert";
Item[] items;
GildedRose(Item[] items) {
@ -15,29 +21,39 @@ class GildedRose {
void updateQuality() {
of(items).forEach(item -> {
// legendary items should not be sold
if (itemNotLegendary(item)) item.sellIn--;
InventoryItem inventoryItem = inventoryFromItem(item);
// reduce sellIn
item.sellIn = inventoryItem.reduceSellIn();
// increase quality when quality decrease is inverted
if (includesItems(item, getInventoriesWithInvertedQualityDecrease())) {
increaseQualityBelowMaximum(item);
// increase backstage passes
increaseBackstagePass(item);
if (inventoryItem.qualityDecreaseInverted()) {
item.quality = inventoryItem.increaseQualityBelowMaximum();
}
// decrease average (non-legendary) items
else if (itemNotLegendary(item)) {
// decrease quality based on their decrease amount
range(0, getQualityDecreaseAmount(item)).forEach(i -> decreaseQualityAboveZero(item));
// decrease quality based on their decrease amount
else {
range(0, inventoryItem.qualityDecreaseAmount()).forEach(i -> item.quality = inventoryItem.decreaseQualityAboveZero());
}
if (item.sellIn < 0) {
// increase quality when aged brie
if (itemAgedBrie(item)) increaseQualityBelowMaximum(item);
// when not aged brie, backstage pass or legendary, decrease quality above zero
else decreaseQualityAboveZeroItemsOtherThan(item, BACKSTAGE_PASS, LEGENDARY);
item.quality = inventoryItem.handleQualityAfterSellIn();
}
});
}
private InventoryItem inventoryFromItem(Item item) {
switch (item.name) {
case AGED_BRIE:
return new AgedBrie(item);
case LEGENDARY:
return new Legendary(item);
case CONJURED_ITEM:
return new ConjuredItem(item);
case BACKSTAGE_PASS:
return new BackstagePass(item);
default:
return new DefaultItem(item);
}
}
}

View File

@ -1,17 +0,0 @@
package com.gildedrose;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum Inventory {
AGED_BRIE("Aged Brie", true, 1),
LEGENDARY("Sulfuras, Hand of Ragnaros", false, 0),
CONJURED("Conjured Mana Cake", false, 2),
BACKSTAGE_PASS("Backstage passes to a TAFKAL80ETC concert", true, 1);
private String name;
private boolean qualityDecreaseInverted;
private int qualityDecrease;
}

View File

@ -0,0 +1,29 @@
package com.gildedrose.domain;
import com.gildedrose.Item;
import com.gildedrose.service.InventoryItem;
public class AgedBrie extends InventoryItem {
public AgedBrie(Item item) {
setName(item.name);
setSellIn(item.sellIn);
setQuality(item.quality);
}
@Override
public boolean qualityDecreaseInverted() {
return true;
}
@Override
public int qualityDecreaseAmount() {
return 1;
}
@Override
public int handleQualityAfterSellIn() {
quality = increaseQualityBelowMaximum();
return quality;
}
}

View File

@ -0,0 +1,53 @@
package com.gildedrose.domain;
import com.gildedrose.Item;
import com.gildedrose.service.InventoryItem;
public class BackstagePass extends InventoryItem {
public BackstagePass(Item item) {
setName(item.name);
setSellIn(item.sellIn);
setQuality(item.quality);
}
@Override
public boolean qualityDecreaseInverted() {
return true;
}
@Override
public int qualityDecreaseAmount() {
return 1;
}
@Override
public int handleQualityAfterSellIn() {
quality = 0;
return quality;
}
@Override
public int increaseQualityBelowMaximum() {
quality = increaseQualityIfNotMaximum();
// increase backstage pass further when sellIn date approaches
quality = increaseBackstagePass();
return quality;
}
private int increaseBackstagePass() {
if (sellIn < 10) {
quality = increaseQualityIfNotMaximum();
if (sellIn < 5) {
quality = increaseQualityIfNotMaximum();
}
}
return quality;
}
private int increaseQualityIfNotMaximum() {
return super.increaseQualityBelowMaximum();
}
}

View File

@ -0,0 +1,29 @@
package com.gildedrose.domain;
import com.gildedrose.Item;
import com.gildedrose.service.InventoryItem;
public class ConjuredItem extends InventoryItem {
public ConjuredItem(Item item) {
setName(item.name);
setSellIn(item.sellIn);
setQuality(item.quality);
}
@Override
public boolean qualityDecreaseInverted() {
return false;
}
@Override
public int qualityDecreaseAmount() {
return 2;
}
@Override
public int handleQualityAfterSellIn() {
quality = decreaseQualityAboveZero();
return quality;
}
}

View File

@ -0,0 +1,29 @@
package com.gildedrose.domain;
import com.gildedrose.Item;
import com.gildedrose.service.InventoryItem;
public class DefaultItem extends InventoryItem {
public DefaultItem(Item item) {
setName(item.name);
setSellIn(item.sellIn);
setQuality(item.quality);
}
@Override
public boolean qualityDecreaseInverted() {
return false;
}
@Override
public int qualityDecreaseAmount() {
return 1;
}
@Override
public int handleQualityAfterSellIn() {
quality = decreaseQualityAboveZero();
return quality;
}
}

View File

@ -0,0 +1,39 @@
package com.gildedrose.domain;
import com.gildedrose.Item;
import com.gildedrose.service.InventoryItem;
public class Legendary extends InventoryItem {
public Legendary(Item item) {
super();
setName(item.name);
setSellIn(item.sellIn);
setQuality(item.quality);
}
@Override
public boolean qualityDecreaseInverted() {
return false;
}
@Override
public int qualityDecreaseAmount() {
return 0;
}
@Override
public int handleQualityAfterSellIn() {
return quality;
}
@Override
public int decreaseQualityAboveZero() {
return quality;
}
@Override
public int reduceSellIn() {
return sellIn;
}
}

View File

@ -1,64 +0,0 @@
package com.gildedrose.service;
import com.gildedrose.Inventory;
import com.gildedrose.Item;
import static com.gildedrose.Inventory.*;
import static java.util.stream.Stream.of;
public class InventoryHelper {
private static final int MAX_QUALITY = 50;
public static Inventory[] getInventoriesWithInvertedQualityDecrease() {
return of(Inventory.values())
.filter(Inventory::isQualityDecreaseInverted)
.distinct()
.toArray(Inventory[]::new);
}
public static void decreaseQualityAboveZeroItemsOtherThan(Item item, Inventory... inventories) {
if (!includesItems(item, inventories)) {
decreaseQualityAboveZero(item);
} else if (itemNotLegendary(item)) item.quality = 0;
}
public static boolean includesItems(Item item, Inventory... inventories) {
return of(inventories).anyMatch(inventory -> item.name.equals(inventory.getName()));
}
public static boolean itemNotLegendary(Item item) {
return !item.name.equals(LEGENDARY.getName());
}
public static boolean itemAgedBrie(Item item) {
return item.name.equals(AGED_BRIE.getName());
}
public static int getQualityDecreaseAmount(Item item) {
return of(Inventory.values())
.filter(inventory -> inventory.getName().equals(item.name))
.findFirst()
.map(Inventory::getQualityDecrease)
.orElse(1);
}
public static void decreaseQualityAboveZero(Item item) {
item.quality = item.quality > 0 ? item.quality - 1 : 0;
}
public static void increaseQualityBelowMaximum(Item item) {
if (item.quality < MAX_QUALITY) {
item.quality++;
}
}
public static void increaseBackstagePass(Item item) {
if (item.name.equals(BACKSTAGE_PASS.getName()) && item.sellIn < 10) {
increaseQualityBelowMaximum(item);
if (item.sellIn < 5) {
increaseQualityBelowMaximum(item);
}
}
}
}

View File

@ -0,0 +1,37 @@
package com.gildedrose.service;
import lombok.NoArgsConstructor;
import lombok.Setter;
@NoArgsConstructor
@Setter
public abstract class InventoryItem {
private static final int MAX_QUALITY = 50;
public String name;
public int quality;
public int sellIn;
public abstract boolean qualityDecreaseInverted();
public abstract int qualityDecreaseAmount();
public abstract int handleQualityAfterSellIn();
public int decreaseQualityAboveZero() {
quality = quality > 0 ? quality - 1 : 0;
return quality;
}
public int increaseQualityBelowMaximum() {
if (quality < MAX_QUALITY) {
quality++;
}
return quality;
}
public int reduceSellIn() {
sellIn--;
return sellIn;
}
}