mirror of
https://github.com/emilybache/GildedRose-Refactoring-Kata.git
synced 2026-02-18 07:51:29 +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 {
|
||||
Item[] items;
|
||||
|
||||
private final QualityUpdater qualityUpdater = new QualityUpdater();
|
||||
|
||||
public GildedRose(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
qualityUpdater.updateQuality(items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 static org.junit.jupiter.api.Assertions.assertAll;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class GildedRoseTest {
|
||||
|
||||
@Test
|
||||
void foo() {
|
||||
Item[] items = new Item[] { new Item("foo", 0, 0) };
|
||||
void testAgedBrieItems() {
|
||||
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);
|
||||
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