mirror of
https://github.com/emilybache/GildedRose-Refactoring-Kata.git
synced 2026-02-19 08:21:37 +00:00
Refactor / redesign:
- Moved 'updateQuality' related code to another class (QualityUpdater); - Introduced 'Category' for an Item category, which specifies how an Item should update its quality; - Introduced 'StandardQualityDegrader' for Default Category and for 'Conjured' items which degrade twice as fast; - Completed tests.
This commit is contained in:
parent
1d0671a186
commit
0ca0110ef3
27
Java/src/main/java/com/gildedrose/Category.java
Normal file
27
Java/src/main/java/com/gildedrose/Category.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package com.gildedrose;
|
||||||
|
|
||||||
|
import java.util.function.ToIntFunction;
|
||||||
|
|
||||||
|
public class Category {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private ToIntFunction<Item> updateQualityFunction;
|
||||||
|
|
||||||
|
public Category(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Category withQualityUpdater(ToIntFunction<Item> updateQualityFunction) {
|
||||||
|
this.updateQualityFunction = updateQualityFunction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isItemMyCategory(String itemName) {
|
||||||
|
return itemName != null && itemName.toLowerCase().startsWith(name.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateItem(Item item) {
|
||||||
|
item.sellIn--;
|
||||||
|
item.quality = Math.max(0, Math.min(50, updateQualityFunction.applyAsInt(item)));
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Java/src/main/java/com/gildedrose/DefaultCategory.java
Normal file
9
Java/src/main/java/com/gildedrose/DefaultCategory.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package com.gildedrose;
|
||||||
|
|
||||||
|
public class DefaultCategory extends Category {
|
||||||
|
|
||||||
|
public DefaultCategory() {
|
||||||
|
super(null);
|
||||||
|
withQualityUpdater(new StandardQualityDegrader());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,60 +3,13 @@ package com.gildedrose;
|
|||||||
class GildedRose {
|
class GildedRose {
|
||||||
Item[] items;
|
Item[] items;
|
||||||
|
|
||||||
|
private final QualityUpdater qualityUpdater = new QualityUpdater();
|
||||||
|
|
||||||
public GildedRose(Item[] items) {
|
public GildedRose(Item[] items) {
|
||||||
this.items = items;
|
this.items = items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateQuality() {
|
public void updateQuality() {
|
||||||
for (int i = 0; i < items.length; i++) {
|
qualityUpdater.updateQuality(items);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
13
Java/src/main/java/com/gildedrose/LegendaryCategory.java
Normal file
13
Java/src/main/java/com/gildedrose/LegendaryCategory.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package com.gildedrose;
|
||||||
|
|
||||||
|
public class LegendaryCategory extends Category {
|
||||||
|
|
||||||
|
public LegendaryCategory(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateItem(Item item) {
|
||||||
|
// Legendary Items never alter
|
||||||
|
}
|
||||||
|
}
|
||||||
55
Java/src/main/java/com/gildedrose/QualityUpdater.java
Normal file
55
Java/src/main/java/com/gildedrose/QualityUpdater.java
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package com.gildedrose;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class QualityUpdater {
|
||||||
|
|
||||||
|
// The 'categories' form the actual quality update specifications:
|
||||||
|
private final Category[] categories = new Category[] {
|
||||||
|
// "Aged Brie" actually increases in Quality the older it gets:
|
||||||
|
new Category("Aged Brie")
|
||||||
|
.withQualityUpdater(item -> item.quality + 1),
|
||||||
|
|
||||||
|
// "Backstage passes", like aged brie, increases in Quality as its SellIn value approaches.
|
||||||
|
// Quality increases by 2 when there are 10 days or less and by 3 when there are 5 days or less but
|
||||||
|
// Quality drops to 0 after the concert:
|
||||||
|
new Category("Backstage passes")
|
||||||
|
.withQualityUpdater(item -> {
|
||||||
|
if (item.sellIn < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (item.sellIn < 5) {
|
||||||
|
return item.quality + 3;
|
||||||
|
}
|
||||||
|
if (item.sellIn < 10) {
|
||||||
|
return item.quality + 2;
|
||||||
|
}
|
||||||
|
return item.quality + 1;
|
||||||
|
}),
|
||||||
|
|
||||||
|
// "Sulfuras", being a legendary item, never has to be sold or decreases in Quality:
|
||||||
|
new LegendaryCategory("Sulfuras"),
|
||||||
|
|
||||||
|
// "Conjured" items degrade in Quality twice as fast as normal items:
|
||||||
|
new Category("Conjured")
|
||||||
|
.withQualityUpdater(new StandardQualityDegrader(2))
|
||||||
|
};
|
||||||
|
|
||||||
|
// Maps an Item name to a specific Category,
|
||||||
|
// only to improve `findCategory()` in terms of speed:
|
||||||
|
private final Map<String, Category> categoryByItemName = new HashMap<>();
|
||||||
|
|
||||||
|
public void updateQuality(Item[] items) {
|
||||||
|
Arrays.stream(items)
|
||||||
|
.forEach(item -> categoryByItemName.computeIfAbsent(item.name, this::findCategory).updateItem(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Category findCategory(String itemName) {
|
||||||
|
return Arrays.stream(categories)
|
||||||
|
.filter(category -> category.isItemMyCategory(itemName))
|
||||||
|
.findFirst()
|
||||||
|
.orElseGet(DefaultCategory::new);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.gildedrose;
|
||||||
|
|
||||||
|
import java.util.function.ToIntFunction;
|
||||||
|
|
||||||
|
public class StandardQualityDegrader implements ToIntFunction<Item> {
|
||||||
|
|
||||||
|
private final int speed;
|
||||||
|
|
||||||
|
public StandardQualityDegrader() {
|
||||||
|
this(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StandardQualityDegrader(int speed) {
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int applyAsInt(Item item) {
|
||||||
|
// Once the sell by date has passed, Quality degrades twice as fast:
|
||||||
|
return item.sellIn >= 0 ? item.quality - speed : item.quality - speed * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,16 +2,118 @@ package com.gildedrose;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertAll;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
class GildedRoseTest {
|
class GildedRoseTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void foo() {
|
void testAgedBrieItems() {
|
||||||
Item[] items = new Item[] { new Item("foo", 0, 0) };
|
Item[] items = new Item[] {
|
||||||
|
new Item("Aged Brie", 100, 10),
|
||||||
|
new Item("Aged Brie", 10, 40),
|
||||||
|
new Item("Aged Brie", 2, 49),
|
||||||
|
new Item("Aged Brie", 1, 50),
|
||||||
|
};
|
||||||
|
|
||||||
GildedRose app = new GildedRose(items);
|
GildedRose app = new GildedRose(items);
|
||||||
app.updateQuality();
|
app.updateQuality();
|
||||||
assertEquals("fixme", app.items[0].name);
|
|
||||||
|
assertItem(items[0], "Aged Brie", 99, 11);
|
||||||
|
assertItem(items[1], "Aged Brie", 9, 41);
|
||||||
|
assertItem(items[2], "Aged Brie", 1, 50);
|
||||||
|
assertItem(items[3], "Aged Brie", 0, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSulfurasItems() {
|
||||||
|
Item[] items = new Item[] {
|
||||||
|
new Item("Sulfuras, Hand of Ragnaros", 100, 80),
|
||||||
|
new Item("Sulfuras, Hand of Ragnaros", -1, 80),
|
||||||
|
};
|
||||||
|
|
||||||
|
GildedRose app = new GildedRose(items);
|
||||||
|
app.updateQuality();
|
||||||
|
|
||||||
|
assertItem(items[0], "Sulfuras, Hand of Ragnaros", 100, 80);
|
||||||
|
assertItem(items[1], "Sulfuras, Hand of Ragnaros", -1, 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBackstagePassesItems() {
|
||||||
|
Item[] items = new Item[] {
|
||||||
|
new Item("Backstage passes to a TAFKAL80ETC concert", 11, 5),
|
||||||
|
new Item("Backstage passes to a TAFKAL80ETC concert", 10, 5),
|
||||||
|
new Item("Backstage passes to a TAFKAL80ETC concert", 9, 5),
|
||||||
|
new Item("Backstage passes to a TAFKAL80ETC concert", 6, 5),
|
||||||
|
new Item("Backstage passes to a TAFKAL80ETC concert", 5, 5),
|
||||||
|
new Item("Backstage passes to a TAFKAL80ETC concert", 4, 5),
|
||||||
|
new Item("Backstage passes to a TAFKAL80ETC concert", 1, 5),
|
||||||
|
new Item("Backstage passes to a TAFKAL80ETC concert", 0, 5),
|
||||||
|
};
|
||||||
|
|
||||||
|
GildedRose app = new GildedRose(items);
|
||||||
|
app.updateQuality();
|
||||||
|
|
||||||
|
assertItem(items[0], "Backstage passes to a TAFKAL80ETC concert", 10, 6);
|
||||||
|
assertItem(items[1], "Backstage passes to a TAFKAL80ETC concert", 9, 7);
|
||||||
|
assertItem(items[2], "Backstage passes to a TAFKAL80ETC concert", 8, 7);
|
||||||
|
assertItem(items[3], "Backstage passes to a TAFKAL80ETC concert", 5, 7);
|
||||||
|
assertItem(items[4], "Backstage passes to a TAFKAL80ETC concert", 4, 8);
|
||||||
|
assertItem(items[5], "Backstage passes to a TAFKAL80ETC concert", 3, 8);
|
||||||
|
assertItem(items[6], "Backstage passes to a TAFKAL80ETC concert", 0, 8);
|
||||||
|
assertItem(items[7], "Backstage passes to a TAFKAL80ETC concert", -1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testStandardItems() {
|
||||||
|
Item[] items = new Item[] {
|
||||||
|
new Item("NoParticularName", 25, 30),
|
||||||
|
new Item("NoParticularName", 1, 30),
|
||||||
|
new Item("NoParticularName", 0, 30),
|
||||||
|
new Item("NoParticularName", -1, 30),
|
||||||
|
new Item("NoParticularName", 1, 1),
|
||||||
|
new Item("NoParticularName", 0, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
GildedRose app = new GildedRose(items);
|
||||||
|
app.updateQuality();
|
||||||
|
|
||||||
|
assertItem(items[0], "NoParticularName", 24, 29);
|
||||||
|
assertItem(items[1], "NoParticularName", 0, 29);
|
||||||
|
assertItem(items[2], "NoParticularName", -1, 28);
|
||||||
|
assertItem(items[3], "NoParticularName", -2, 28);
|
||||||
|
assertItem(items[4], "NoParticularName", 0, 0);
|
||||||
|
assertItem(items[5], "NoParticularName", -1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConjuredItems() {
|
||||||
|
Item[] items = new Item[] {
|
||||||
|
new Item("Conjured Mana Cake", 25, 30),
|
||||||
|
new Item("Conjured Mana Cake", 1, 30),
|
||||||
|
new Item("Conjured Mana Cake", 0, 30),
|
||||||
|
new Item("Conjured Mana Cake", -1, 30),
|
||||||
|
new Item("Conjured Mana Cake", 1, 1),
|
||||||
|
new Item("Conjured Mana Cake", 0, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
GildedRose app = new GildedRose(items);
|
||||||
|
app.updateQuality();
|
||||||
|
|
||||||
|
assertItem(items[0], "Conjured Mana Cake", 24, 28);
|
||||||
|
assertItem(items[1], "Conjured Mana Cake", 0, 28);
|
||||||
|
assertItem(items[2], "Conjured Mana Cake", -1, 26);
|
||||||
|
assertItem(items[3], "Conjured Mana Cake", -2, 26);
|
||||||
|
assertItem(items[4], "Conjured Mana Cake", 0, 0);
|
||||||
|
assertItem(items[5], "Conjured Mana Cake", -1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertItem(Item item, String name, int sellIn, int quality) {
|
||||||
|
assertAll(
|
||||||
|
() -> assertEquals(name, item.name, "item name"),
|
||||||
|
() -> assertEquals(sellIn, item.sellIn, "item sellIn"),
|
||||||
|
() -> assertEquals(quality, item.quality, "item quality")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user