mirror of
https://github.com/emilybache/GildedRose-Refactoring-Kata.git
synced 2026-02-18 16:01:42 +00:00
refactored with strategy pattern + factory and added test cases
This commit is contained in:
parent
f80413c2fd
commit
2332d4e30e
@ -1,69 +1,11 @@
|
||||
export class Item {
|
||||
name: string;
|
||||
sellIn: number;
|
||||
quality: number;
|
||||
|
||||
constructor(name, sellIn, quality) {
|
||||
this.name = name;
|
||||
this.sellIn = sellIn;
|
||||
this.quality = quality;
|
||||
}
|
||||
}
|
||||
|
||||
import Item from "./models/Item";
|
||||
import { UpdateStrategyFactory } from "./updateStrategyFactory";
|
||||
export class GildedRose {
|
||||
items: Array<Item>;
|
||||
private constructor() {}
|
||||
|
||||
constructor(items = [] as Array<Item>) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
updateQuality() {
|
||||
for (let i = 0; i < this.items.length; i++) {
|
||||
if (this.items[i].name != 'Aged Brie' && this.items[i].name != 'Backstage passes to a TAFKAL80ETC concert') {
|
||||
if (this.items[i].quality > 0) {
|
||||
if (this.items[i].name != 'Sulfuras, Hand of Ragnaros') {
|
||||
this.items[i].quality = this.items[i].quality - 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.items[i].quality < 50) {
|
||||
this.items[i].quality = this.items[i].quality + 1
|
||||
if (this.items[i].name == 'Backstage passes to a TAFKAL80ETC concert') {
|
||||
if (this.items[i].sellIn < 11) {
|
||||
if (this.items[i].quality < 50) {
|
||||
this.items[i].quality = this.items[i].quality + 1
|
||||
}
|
||||
}
|
||||
if (this.items[i].sellIn < 6) {
|
||||
if (this.items[i].quality < 50) {
|
||||
this.items[i].quality = this.items[i].quality + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.items[i].name != 'Sulfuras, Hand of Ragnaros') {
|
||||
this.items[i].sellIn = this.items[i].sellIn - 1;
|
||||
}
|
||||
if (this.items[i].sellIn < 0) {
|
||||
if (this.items[i].name != 'Aged Brie') {
|
||||
if (this.items[i].name != 'Backstage passes to a TAFKAL80ETC concert') {
|
||||
if (this.items[i].quality > 0) {
|
||||
if (this.items[i].name != 'Sulfuras, Hand of Ragnaros') {
|
||||
this.items[i].quality = this.items[i].quality - 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.items[i].quality = this.items[i].quality - this.items[i].quality
|
||||
}
|
||||
} else {
|
||||
if (this.items[i].quality < 50) {
|
||||
this.items[i].quality = this.items[i].quality + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.items;
|
||||
static updateQuality(items = [] as Array<Item>) {
|
||||
let updatedItems = items.map(
|
||||
item => UpdateStrategyFactory.getUpdateStrategy(item).updateItem(item));
|
||||
return updatedItems;
|
||||
}
|
||||
}
|
||||
|
||||
11
TypeScript/app/models/Item.ts
Normal file
11
TypeScript/app/models/Item.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export default class Item {
|
||||
name: string;
|
||||
sellIn: number;
|
||||
quality: number;
|
||||
|
||||
constructor(name, sellIn, quality) {
|
||||
this.name = name;
|
||||
this.sellIn = sellIn;
|
||||
this.quality = quality;
|
||||
}
|
||||
}
|
||||
12
TypeScript/app/updateStrategies/AgedBrieStrategy.ts
Normal file
12
TypeScript/app/updateStrategies/AgedBrieStrategy.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import Item from "./../models/Item";
|
||||
import IUpdateStrategy from "./IUpdateStrategy";
|
||||
|
||||
export default class AgedBrieStrategy implements IUpdateStrategy {
|
||||
constructor(private qualityFactor : number) {}
|
||||
|
||||
updateItem(item: Item) : Item {
|
||||
let quality = Math.min(50, item.quality + 1 * this.qualityFactor);
|
||||
let sellIn = item.sellIn - 1;
|
||||
return new Item(item.name, sellIn, quality);
|
||||
}
|
||||
}
|
||||
20
TypeScript/app/updateStrategies/BackstagePassStrategy.ts
Normal file
20
TypeScript/app/updateStrategies/BackstagePassStrategy.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import Item from "./../models/Item";
|
||||
import IUpdateStrategy from "./IUpdateStrategy";
|
||||
|
||||
export default class BackstagePassStrategy implements IUpdateStrategy {
|
||||
updateItem(item: Item) : Item {
|
||||
let increaseFactor = this.getIncreaseFactor(item.sellIn);
|
||||
let newQuality =
|
||||
increaseFactor
|
||||
? Math.min(50, item.quality + increaseFactor)
|
||||
: 0;
|
||||
let newSellIn = item.sellIn - 1;
|
||||
return new Item(item.name, newSellIn, newQuality);
|
||||
}
|
||||
|
||||
private getIncreaseFactor(sellIn: number){
|
||||
if (sellIn > 10) return 1;
|
||||
if (sellIn <= 10 && sellIn > 5) return 2;
|
||||
if (sellIn <= 5 && sellIn > 0) return 3;
|
||||
}
|
||||
}
|
||||
13
TypeScript/app/updateStrategies/DefaultStrategy.ts
Normal file
13
TypeScript/app/updateStrategies/DefaultStrategy.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import Item from "./../models/Item";
|
||||
import IUpdateStrategy from "./IUpdateStrategy";
|
||||
|
||||
|
||||
export default class DefaultStrategy implements IUpdateStrategy {
|
||||
constructor(private qualityFactor : number) {}
|
||||
|
||||
updateItem(item: Item) : Item {
|
||||
let newQuality = Math.max(0, item.quality - this.qualityFactor);
|
||||
let newSellIn = item.sellIn - 1;
|
||||
return new Item(item.name, newSellIn, newQuality);
|
||||
}
|
||||
}
|
||||
6
TypeScript/app/updateStrategies/IUpdateStrategy.ts
Normal file
6
TypeScript/app/updateStrategies/IUpdateStrategy.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import Item from "./../models/Item";
|
||||
|
||||
|
||||
export default interface IUpdateStrategy {
|
||||
updateItem(item: Item) : Item;
|
||||
}
|
||||
8
TypeScript/app/updateStrategies/NoUpdateStrategy.ts
Normal file
8
TypeScript/app/updateStrategies/NoUpdateStrategy.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import Item from "@/models/Item";
|
||||
import IUpdateStrategy from "./IUpdateStrategy";
|
||||
|
||||
export default class NoUpdateStrategy implements IUpdateStrategy {
|
||||
updateItem(item: Item) : Item {
|
||||
return new Item(item.name, item.sellIn, item.quality);
|
||||
}
|
||||
}
|
||||
12
TypeScript/app/updateStrategies/conjuredStrategy.ts
Normal file
12
TypeScript/app/updateStrategies/conjuredStrategy.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import Item from "./../models/Item";
|
||||
import IUpdateStrategy from "./IUpdateStrategy";
|
||||
|
||||
export default class ConjuredStrategy implements IUpdateStrategy {
|
||||
constructor(private qualityFactor : number) {}
|
||||
|
||||
updateItem(item: Item) : Item {
|
||||
let quality = Math.max(0, item.quality - 2 * this.qualityFactor);
|
||||
let sellIn = item.sellIn - 1;
|
||||
return new Item(item.name, sellIn, quality);
|
||||
}
|
||||
}
|
||||
27
TypeScript/app/updateStrategyFactory.ts
Normal file
27
TypeScript/app/updateStrategyFactory.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import Item from "./models/Item";
|
||||
import AgedBrieStrategy from "./updateStrategies/AgedBrieStrategy";
|
||||
import BackstagePassStrategy from "./updateStrategies/BackstagePassStrategy";
|
||||
import ConjuredStrategy from "./updateStrategies/conjuredStrategy";
|
||||
import DefaultStrategy from "./updateStrategies/DefaultStrategy";
|
||||
import IUpdateStrategy from "./updateStrategies/IUpdateStrategy";
|
||||
import NoUpdateStrategy from "./updateStrategies/NoUpdateStrategy";
|
||||
|
||||
export class UpdateStrategyFactory {
|
||||
static getUpdateStrategy(item: Item): IUpdateStrategy {
|
||||
|
||||
let qualityFactor = item.sellIn <= 0 ? 2 : 1;
|
||||
|
||||
switch (item.name) {
|
||||
case 'Aged Brie':
|
||||
return new AgedBrieStrategy(qualityFactor);
|
||||
case 'Sulfuras, Hand of Ragnaros':
|
||||
return new NoUpdateStrategy();
|
||||
case 'Backstage passes to a TAFKAL80ETC concert':
|
||||
return new BackstagePassStrategy();
|
||||
case 'conjured':
|
||||
return new ConjuredStrategy(qualityFactor);
|
||||
default:
|
||||
return new DefaultStrategy(qualityFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
import { Item, GildedRose } from '../app/gilded-rose';
|
||||
import { GildedRose } from '../app/gilded-rose';
|
||||
import Item from "../app/models/Item";
|
||||
|
||||
const items = [
|
||||
new Item("+5 Dexterity Vest", 10, 20), //
|
||||
@ -12,9 +13,6 @@ const items = [
|
||||
// this conjured item does not work properly yet
|
||||
new Item("Conjured Mana Cake", 3, 6)];
|
||||
|
||||
|
||||
const gildedRose = new GildedRose(items);
|
||||
|
||||
let days: number = 2;
|
||||
if (process.argv.length > 2) {
|
||||
days = +process.argv[2];
|
||||
@ -28,5 +26,5 @@ for (let i = 0; i < days; i++) {
|
||||
|
||||
});
|
||||
console.log();
|
||||
gildedRose.updateQuality();
|
||||
GildedRose.updateQuality(items);
|
||||
}
|
||||
|
||||
@ -1,9 +1,46 @@
|
||||
import { Item, GildedRose } from '@/gilded-rose';
|
||||
import { GildedRose } from '@/gilded-rose';
|
||||
import Item from "@/models/Item";
|
||||
|
||||
describe('Gilded Rose', () => {
|
||||
it('should foo', () => {
|
||||
const gildedRose = new GildedRose([new Item('foo', 0, 0)]);
|
||||
const items = gildedRose.updateQuality();
|
||||
expect(items[0].name).toBe('fixme');
|
||||
});
|
||||
it.each`
|
||||
name | quality | expectedQuality | sellIn | expectedSellIn | description
|
||||
${'abc def'} | ${0} | ${0} | ${8} | ${7} | ${"quality should not be negative"}
|
||||
${'abc def'} | ${0} | ${0} | ${0} | ${-1} | ${"sellIn should decrease"}
|
||||
${'abc def'} | ${8} | ${6} | ${0} | ${-1} | ${"quality should decrease twice after sellIn is negative"}
|
||||
${'Aged Brie'} | ${0} | ${1} | ${8} | ${7} | ${"should increase quality by 1"}
|
||||
${'Aged Brie'} | ${0} | ${2} | ${0} | ${-1} | ${"should increase quality by 1"}
|
||||
${'Aged Brie'} | ${50} | ${50} | ${8} | ${7} | ${"quality should not be higher than 50"}
|
||||
${'conjured'} | ${0} | ${0} | ${8} | ${7} | ${"quality should not be negative"}
|
||||
${'conjured'} | ${0} | ${0} | ${0} | ${-1} | ${"quality should not be negative"}
|
||||
${'conjured'} | ${4} | ${2} | ${8} | ${7} | ${"quality should decrease by 2"}
|
||||
${'conjured'} | ${4} | ${0} | ${0} | ${-1} | ${"quality should decrease by 4 when sellIn is <= 0"}
|
||||
${'Sulfuras, Hand of Ragnaros'} | ${10} | ${10} | ${10} | ${10} | ${"should not change "}
|
||||
${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${11}| ${11} | ${10} | ${"quality increases by 1 for sellIn > 10"}
|
||||
${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${11}| ${30} | ${29} | ${"quality increases by 1 for sellIn > 10"}
|
||||
${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${12}| ${10} | ${9} | ${"quality increases by 2 for sellIn <= 10 && > 5"}
|
||||
${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${12}| ${6} | ${5} | ${"quality increases by 2 for sellIn <= 10 && > 5"}
|
||||
${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${13}| ${5} | ${4} | ${"quality increases by 3 for sellIn <= 5 && >= 0"}
|
||||
${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${13}| ${1} | ${0} | ${"quality increases by 3 for sellIn <= 5 && > 0"}
|
||||
${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${0} | ${0} | ${-1} | ${"quality is 0 if sellIn is exceeded"}
|
||||
${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${0} | ${-1} | ${-2} | ${"quality is 0 if sellIn is exceeded"}
|
||||
`("'$description' for '$name' with quality '$quality' and sellIn '$sellIn'", ({name, quality, expectedQuality, sellIn, expectedSellIn, description}) => {
|
||||
const item1 = new Item(name, sellIn, quality);
|
||||
const items = GildedRose.updateQuality([item1]);
|
||||
expect(items[0].name).toBe(name);
|
||||
expect(items[0].quality).toBe(expectedQuality);
|
||||
expect(items[0].sellIn).toBe(expectedSellIn);
|
||||
});
|
||||
|
||||
it("should be correct for 2 items", () => {
|
||||
const item1 = new Item('abc def', 8, 5);
|
||||
const item2 = new Item('Aged Brie', 10, 2);
|
||||
const items = GildedRose.updateQuality([item1, item2]);
|
||||
expect(items[0].name).toBe(item1.name);
|
||||
expect(items[0].quality).toBe(4);
|
||||
expect(items[0].sellIn).toBe(7);
|
||||
expect(items[1].name).toBe(item2.name);
|
||||
expect(items[1].quality).toBe(3);
|
||||
expect(items[1].sellIn).toBe(9);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { expect } from 'chai';
|
||||
import { Item, GildedRose } from '@/gilded-rose';
|
||||
import { GildedRose } from '@/gilded-rose';
|
||||
import Item from "@/models/Item";
|
||||
|
||||
describe('Gilded Rose', () => {
|
||||
it('should foo', () => {
|
||||
const gildedRose = new GildedRose([new Item('foo', 0, 0)]);
|
||||
const items = gildedRose.updateQuality();
|
||||
expect(items[0].name).to.equal('fixme');
|
||||
// const gildedRose = new GildedRose([new Item('foo', 0, 0)]);
|
||||
// const items = gildedRose.updateQuality();
|
||||
expect("items[0].name").to.equal('fixme');
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user