| | 1 | = 2013-05-10日,2013-05-17日 Code Kata活动 = |
| | 2 | 为了提高论坛组developer的开发热情,提升developer的开发能力,增强developer协作与沟通能力,论坛组manager李峰,组织了一次Code Kata活动。题目由组员各自挑选一个,挑选之后汇总[[BR]] |
| | 3 | 最后由大家无记名投票的方式选举出一个题目,由丁健勇贡献的题目贴近生活,有趣味,难度适中。最后以较高票数中标。题目如下:[[BR]] |
| | 4 | |
| | 5 | {{{ |
| | 6 | 饭堂排队吃饭。 |
| | 7 | |
| | 8 | 饭堂排队吃饭,有11元,13元,15元3个窗口。 |
| | 9 | |
| | 10 | 公司有500人就餐,其中250人第一选择是11元窗口,150人第一选择是13元窗口,100人第一选择是10元窗口。 |
| | 11 | |
| | 12 | 假设每分钟11元窗口可打饭3人,13元窗口可打饭2人,15元窗口可打饭1人,每分钟有10名员工依次进场。 |
| | 13 | |
| | 14 | 由于人的排队耐心有限,所以假如11元窗口的队伍人数大于50人时,员工会选择13元窗口,当13元窗口的队伍人数大于30人时,员工会选择15元窗口, |
| | 15 | 当15元窗口人数大于15人时,员工则不会再等待,直接出外就餐。 |
| | 16 | |
| | 17 | 求出饭堂的营业额。 |
| | 18 | }}} |
| | 19 | |
| | 20 | Code Kata要求大家用测试驱动开发的模式来完成题目,最后依靠小组成员非凡的智慧与良好的职业素质,最后成功地完成了这一次Code Kata活动。 |
| | 21 | [[BR]] |
| | 22 | 测试代码如下: |
| | 23 | {{{ |
| | 24 | /* |
| | 25 | * To change this template, choose Tools | Templates |
| | 26 | * and open the template in the editor. |
| | 27 | */ |
| | 28 | package lunch; |
| | 29 | |
| | 30 | import java.util.HashMap; |
| | 31 | import java.util.LinkedList; |
| | 32 | import java.util.List; |
| | 33 | import java.util.Map; |
| | 34 | import org.junit.After; |
| | 35 | import org.junit.AfterClass; |
| | 36 | import org.junit.Assert; |
| | 37 | import org.junit.Before; |
| | 38 | import org.junit.BeforeClass; |
| | 39 | import org.junit.Test; |
| | 40 | import static org.junit.Assert.*; |
| | 41 | |
| | 42 | /** |
| | 43 | * |
| | 44 | * @author pc |
| | 45 | */ |
| | 46 | public class LunchTest { |
| | 47 | |
| | 48 | private Lunch lunch = null; |
| | 49 | private LinkedList<String> list; |
| | 50 | |
| | 51 | public LunchTest() { |
| | 52 | } |
| | 53 | |
| | 54 | @BeforeClass |
| | 55 | public static void setUpClass() { |
| | 56 | } |
| | 57 | |
| | 58 | @AfterClass |
| | 59 | public static void tearDownClass() { |
| | 60 | } |
| | 61 | |
| | 62 | @Before |
| | 63 | public void setUp() { |
| | 64 | lunch = new Lunch(); |
| | 65 | list = lunch.getPeople(); |
| | 66 | list.offer("11"); |
| | 67 | list.offer("13"); |
| | 68 | list.offer("11"); |
| | 69 | list.offer("11"); |
| | 70 | list.offer("15"); |
| | 71 | list.offer("15"); |
| | 72 | list.offer("11"); |
| | 73 | list.offer("13"); |
| | 74 | list.offer("13"); |
| | 75 | list.offer("13"); |
| | 76 | |
| | 77 | list.offer("13"); |
| | 78 | list.offer("13"); |
| | 79 | list.offer("13"); |
| | 80 | list.offer("13"); |
| | 81 | list.offer("15"); |
| | 82 | list.offer("15"); |
| | 83 | list.offer("11"); |
| | 84 | list.offer("13"); |
| | 85 | list.offer("13"); |
| | 86 | list.offer("13"); |
| | 87 | } |
| | 88 | |
| | 89 | @After |
| | 90 | public void tearDown() { |
| | 91 | } |
| | 92 | |
| | 93 | |
| | 94 | @Test |
| | 95 | public void testInit() { |
| | 96 | lunch = new Lunch(); |
| | 97 | lunch.init(); |
| | 98 | List<String> people = lunch.getPeople(); |
| | 99 | Assert.assertEquals(Lunch.TOTAL_PEOPLE, lunch.getPeople().size()); |
| | 100 | int count11 = 0; |
| | 101 | int count13 = 0; |
| | 102 | int count15 = 0; |
| | 103 | for (String s : people) { |
| | 104 | if ("11".equals(s)) { |
| | 105 | count11++; |
| | 106 | } |
| | 107 | if ("13".equals(s)) { |
| | 108 | count13++; |
| | 109 | } |
| | 110 | if ("15".equals(s)) { |
| | 111 | count15++; |
| | 112 | } |
| | 113 | } |
| | 114 | //TODO 验证首选11元的人数 |
| | 115 | Assert.assertEquals(Lunch.TOTAL_PEOPLE_11, count11); |
| | 116 | |
| | 117 | //TODO 验证首选13元的人数 |
| | 118 | Assert.assertEquals(Lunch.TOTAL_PEOPLE_13, count13); |
| | 119 | |
| | 120 | //TODO 验证首选15元的人数 |
| | 121 | Assert.assertEquals(Lunch.TOTAL_PEOPLE_15, count15); |
| | 122 | |
| | 123 | //TODO 验证随机 |
| | 124 | |
| | 125 | } |
| | 126 | |
| | 127 | @Test |
| | 128 | public void testCheckpoint() { |
| | 129 | //lunch.init(); |
| | 130 | |
| | 131 | Map<String, Integer> queue = lunch.getQueue(); |
| | 132 | queue.put("11", 0); |
| | 133 | queue.put("13", 0); |
| | 134 | queue.put("15", 0); |
| | 135 | lunch.setQueue(queue); |
| | 136 | |
| | 137 | lunch.checkpoint(); |
| | 138 | Assert.assertEquals(10, list.size()); |
| | 139 | Assert.assertEquals(1, (int) queue.get("11")); |
| | 140 | Assert.assertEquals(2, (int) queue.get("13")); |
| | 141 | Assert.assertEquals(1, (int) queue.get("15")); |
| | 142 | Assert.assertEquals(4, lunch.getPersonCount11()); |
| | 143 | Assert.assertEquals(4, lunch.getPersonCount13()); |
| | 144 | Assert.assertEquals(2, lunch.getPersonCount15()); |
| | 145 | |
| | 146 | lunch.checkpoint(); |
| | 147 | Assert.assertEquals(0, list.size()); |
| | 148 | Assert.assertEquals(0, (int) queue.get("11")); |
| | 149 | Assert.assertEquals(7, (int) queue.get("13")); |
| | 150 | Assert.assertEquals(2, (int) queue.get("15")); |
| | 151 | Assert.assertEquals(5, lunch.getPersonCount11()); |
| | 152 | Assert.assertEquals(11, lunch.getPersonCount13()); |
| | 153 | Assert.assertEquals(4, lunch.getPersonCount15()); |
| | 154 | } |
| | 155 | |
| | 156 | @Test |
| | 157 | public void testCheckPointHavePeople() { |
| | 158 | Map<String, Integer> queue = lunch.getQueue(); |
| | 159 | queue.put("11", 50); |
| | 160 | queue.put("13", 30); |
| | 161 | queue.put("15", 10); |
| | 162 | lunch.setQueue(queue); |
| | 163 | |
| | 164 | lunch.checkpoint(); |
| | 165 | Assert.assertEquals(10, list.size()); |
| | 166 | Assert.assertEquals(47, (int) queue.get("11")); |
| | 167 | Assert.assertEquals(28, (int) queue.get("13")); |
| | 168 | Assert.assertEquals(14, (int) queue.get("15")); |
| | 169 | Assert.assertEquals(0, lunch.getPersonCount11()); |
| | 170 | Assert.assertEquals(0, lunch.getPersonCount13()); |
| | 171 | Assert.assertEquals(5, lunch.getPersonCount15()); |
| | 172 | } |
| | 173 | |
| | 174 | @Test |
| | 175 | public void testGetBalance() { |
| | 176 | int balance = lunch.getPersonCount11() * Lunch.COST_ELEVEN |
| | 177 | + lunch.getPersonCount13() * Lunch.COST_THIRTEEN |
| | 178 | + lunch.getPersonCount15() * Lunch.COST_FIFTEEN; |
| | 179 | Assert.assertEquals(balance, lunch.getBalance()); |
| | 180 | } |
| | 181 | |
| | 182 | @Test |
| | 183 | public void testChoose() { |
| | 184 | |
| | 185 | Map<String, Integer> queue = new HashMap<String, Integer>(); |
| | 186 | queue.put("11", 33); |
| | 187 | queue.put("13", 0); |
| | 188 | queue.put("15", 0); |
| | 189 | |
| | 190 | |
| | 191 | String people = "11"; |
| | 192 | lunch.setQueue(queue); |
| | 193 | |
| | 194 | Assert.assertTrue(lunch.choose11(people)); |
| | 195 | |
| | 196 | queue = new HashMap<String, Integer>(); |
| | 197 | queue.put("11", 49); |
| | 198 | queue.put("13", 0); |
| | 199 | queue.put("15", 0); |
| | 200 | lunch.setQueue(queue); |
| | 201 | Assert.assertTrue(lunch.choose11(people)); |
| | 202 | |
| | 203 | queue = new HashMap<String, Integer>(); |
| | 204 | queue.put("11", 50); |
| | 205 | queue.put("13", 0); |
| | 206 | queue.put("15", 0); |
| | 207 | lunch.setQueue(queue); |
| | 208 | Assert.assertFalse(lunch.choose11(people)); |
| | 209 | |
| | 210 | people = "13"; |
| | 211 | Assert.assertFalse(lunch.choose11(people)); |
| | 212 | } |
| | 213 | |
| | 214 | @Test |
| | 215 | public void testChoose13() { |
| | 216 | Map<String, Integer> queue = new HashMap<String, Integer>(); |
| | 217 | |
| | 218 | String people = "13"; |
| | 219 | queue = new HashMap<String, Integer>(); |
| | 220 | queue.put("11", 0); |
| | 221 | queue.put("13", 30); |
| | 222 | queue.put("15", 0); |
| | 223 | lunch.setQueue(queue); |
| | 224 | Assert.assertFalse(lunch.choose13(people)); |
| | 225 | |
| | 226 | queue = new HashMap<String, Integer>(); |
| | 227 | queue.put("11", 0); |
| | 228 | queue.put("13", 29); |
| | 229 | queue.put("15", 0); |
| | 230 | lunch.setQueue(queue); |
| | 231 | Assert.assertTrue(lunch.choose13(people)); |
| | 232 | |
| | 233 | people = "15"; |
| | 234 | Assert.assertFalse(lunch.choose13(people)); |
| | 235 | |
| | 236 | } |
| | 237 | |
| | 238 | @Test |
| | 239 | public void testChoose15() { |
| | 240 | |
| | 241 | Map<String, Integer> queue = new HashMap<String, Integer>(); |
| | 242 | |
| | 243 | String people = "15"; |
| | 244 | queue = new HashMap<String, Integer>(); |
| | 245 | queue.put("11", 0); |
| | 246 | queue.put("13", 0); |
| | 247 | queue.put("15", 15); |
| | 248 | lunch.setQueue(queue); |
| | 249 | Assert.assertFalse(lunch.choose15(people)); |
| | 250 | |
| | 251 | queue = new HashMap<String, Integer>(); |
| | 252 | queue.put("11", 0); |
| | 253 | queue.put("13", 0); |
| | 254 | queue.put("15", 14); |
| | 255 | lunch.setQueue(queue); |
| | 256 | Assert.assertTrue(lunch.choose15(people)); |
| | 257 | } |
| | 258 | |
| | 259 | @Test |
| | 260 | public void testHandlePieceOfLunch(){ |
| | 261 | Map<String, Integer> queue = lunch.getQueue(); |
| | 262 | queue.put("11", 30); |
| | 263 | queue.put("13", 20); |
| | 264 | queue.put("15", 10); |
| | 265 | lunch.setQueue(queue); |
| | 266 | |
| | 267 | lunch.handlePieceOfLunch(); |
| | 268 | Assert.assertEquals(27, (int) queue.get("11")); |
| | 269 | Assert.assertEquals(18, (int) queue.get("13")); |
| | 270 | Assert.assertEquals(9, (int) queue.get("15")); |
| | 271 | |
| | 272 | queue = lunch.getQueue(); |
| | 273 | queue.put("11", 0); |
| | 274 | queue.put("13", 0); |
| | 275 | queue.put("15", 0); |
| | 276 | lunch.setQueue(queue); |
| | 277 | lunch.handlePieceOfLunch(); |
| | 278 | Assert.assertEquals(0, (int) queue.get("11")); |
| | 279 | Assert.assertEquals(0, (int) queue.get("13")); |
| | 280 | Assert.assertEquals(0, (int) queue.get("15")); |
| | 281 | |
| | 282 | queue = lunch.getQueue(); |
| | 283 | queue.put("11", 3); |
| | 284 | queue.put("13", 2); |
| | 285 | queue.put("15", 1); |
| | 286 | lunch.setQueue(queue); |
| | 287 | lunch.handlePieceOfLunch(); |
| | 288 | Assert.assertEquals(0, (int) queue.get("11")); |
| | 289 | Assert.assertEquals(0, (int) queue.get("13")); |
| | 290 | Assert.assertEquals(0, (int) queue.get("15")); |
| | 291 | |
| | 292 | } |
| | 293 | } |
| | 294 | }}} |
| | 295 | |
| | 296 | 源代码如下: |
| | 297 | {{{ |
| | 298 | /* |
| | 299 | * To change this template, choose Tools | Templates |
| | 300 | * and open the template in the editor. |
| | 301 | */ |
| | 302 | package lunch; |
| | 303 | |
| | 304 | import java.util.ArrayList; |
| | 305 | import java.util.Collections; |
| | 306 | import java.util.HashMap; |
| | 307 | import java.util.LinkedList; |
| | 308 | import java.util.List; |
| | 309 | import java.util.Map; |
| | 310 | import java.util.Queue; |
| | 311 | |
| | 312 | /** |
| | 313 | * |
| | 314 | * @author pc |
| | 315 | */ |
| | 316 | public class Lunch { |
| | 317 | |
| | 318 | public static final int WAIT_NUM_OF_11 = 50; |
| | 319 | public static final int WAIT_NUM_OF_13 = 30; |
| | 320 | public static final int WAIT_NUM_OF_15 = 15; |
| | 321 | |
| | 322 | public static final int TOTAL_PEOPLE = 500; |
| | 323 | public static final int TOTAL_PEOPLE_11 = 280; |
| | 324 | public static final int TOTAL_PEOPLE_13 = 150; |
| | 325 | public static final int TOTAL_PEOPLE_15 = 70; |
| | 326 | public static final int COST_ELEVEN = 11; |
| | 327 | public static final int COST_THIRTEEN = 13; |
| | 328 | public static final int COST_FIFTEEN = 15; |
| | 329 | |
| | 330 | public static final int NUM_OF_HANDLE_11 = 3; |
| | 331 | public static final int NUM_OF_HANDLE_13 = 2; |
| | 332 | public static final int NUM_OF_HANDLE_15 = 1; |
| | 333 | |
| | 334 | |
| | 335 | private Map<String, Integer> queue = new HashMap<String, Integer>(); |
| | 336 | private LinkedList<String> people = new LinkedList<String>(); |
| | 337 | |
| | 338 | private int personCount11 = 0; |
| | 339 | private int personCount13 = 0; |
| | 340 | private int personCount15 = 0; |
| | 341 | |
| | 342 | public Map<String, Integer> getQueue() { |
| | 343 | return queue; |
| | 344 | } |
| | 345 | |
| | 346 | public void setQueue(Map<String, Integer> queue) { |
| | 347 | this.queue = queue; |
| | 348 | } |
| | 349 | |
| | 350 | public LinkedList<String> getPeople() { |
| | 351 | return people; |
| | 352 | } |
| | 353 | |
| | 354 | public int getPersonCount11() { |
| | 355 | return personCount11; |
| | 356 | } |
| | 357 | |
| | 358 | public int getPersonCount13() { |
| | 359 | return personCount13; |
| | 360 | } |
| | 361 | |
| | 362 | public int getPersonCount15() { |
| | 363 | return personCount15; |
| | 364 | } |
| | 365 | |
| | 366 | /** |
| | 367 | * 初始化进场顺序 |
| | 368 | */ |
| | 369 | public void init() { |
| | 370 | for (int i = 0; i < TOTAL_PEOPLE_11; i++) { |
| | 371 | people.add("11"); |
| | 372 | } |
| | 373 | for (int i = 0; i < TOTAL_PEOPLE_13; i++) { |
| | 374 | people.add("13"); |
| | 375 | } |
| | 376 | for (int i = 0; i < TOTAL_PEOPLE_15; i++) { |
| | 377 | people.add("15"); |
| | 378 | } |
| | 379 | |
| | 380 | queue.put("11", 0); |
| | 381 | queue.put("13", 0); |
| | 382 | queue.put("15", 0); |
| | 383 | |
| | 384 | Collections.shuffle(people); |
| | 385 | } |
| | 386 | |
| | 387 | public int getBalance() { |
| | 388 | return COST_ELEVEN * personCount11 + COST_THIRTEEN * personCount13 |
| | 389 | + COST_FIFTEEN * personCount15; |
| | 390 | } |
| | 391 | |
| | 392 | /** |
| | 393 | * 每分钟时的处理方法 |
| | 394 | */ |
| | 395 | public void checkpoint() { |
| | 396 | for (int i = 0; i < 10; i++) { |
| | 397 | String p = people.poll(); |
| | 398 | |
| | 399 | // 判断队列人数 |
| | 400 | boolean result = choose11(p); |
| | 401 | if (result) { |
| | 402 | queue.put("11", queue.get("11") + 1); |
| | 403 | personCount11++; |
| | 404 | } else { |
| | 405 | result = choose13(p); |
| | 406 | if (result) { |
| | 407 | queue.put("13", queue.get("13") + 1); |
| | 408 | personCount13++; |
| | 409 | } else { |
| | 410 | if (choose15(p)) { |
| | 411 | queue.put("15", queue.get("15") + 1); |
| | 412 | personCount15++; |
| | 413 | } |
| | 414 | } |
| | 415 | } |
| | 416 | } |
| | 417 | |
| | 418 | handlePieceOfLunch(); |
| | 419 | } |
| | 420 | |
| | 421 | public void handlePieceOfLunch() { |
| | 422 | queue.put("11", queue.get("11") - 3 < 0 ? 0 : queue.get("11") - 3); |
| | 423 | queue.put("13", queue.get("13") - 2 < 0 ? 0 : queue.get("13") - 2); |
| | 424 | queue.put("15", queue.get("15") - 1 < 0 ? 0 : queue.get("15") - 1); |
| | 425 | } |
| | 426 | |
| | 427 | public boolean choose11(String p) { |
| | 428 | return queue.get("11") < WAIT_NUM_OF_11 && "11".equals(p); |
| | 429 | } |
| | 430 | |
| | 431 | public boolean choose13(String p) { |
| | 432 | return queue.get("13") < WAIT_NUM_OF_13 && ("11".equals(p) || "13".equals(p)); |
| | 433 | } |
| | 434 | |
| | 435 | public boolean choose15(String p) { |
| | 436 | return queue.get("15") < WAIT_NUM_OF_15; |
| | 437 | } |
| | 438 | |
| | 439 | /** |
| | 440 | * @param args the command line arguments |
| | 441 | */ |
| | 442 | public static void main(String[] args) { |
| | 443 | // TODO code application logic here |
| | 444 | int times = TOTAL_PEOPLE % 10 == 0 ? TOTAL_PEOPLE / 10 : TOTAL_PEOPLE / 10 + 1; |
| | 445 | Lunch lunch = new Lunch(); |
| | 446 | lunch.init(); |
| | 447 | for (int i = 0; i < times; i++) { |
| | 448 | lunch.checkpoint(); |
| | 449 | } |
| | 450 | int total = lunch.getBalance(); |
| | 451 | System.out.println("total:" + total); |
| | 452 | System.out.println("getPersonCount11:" + lunch.getPersonCount11()); |
| | 453 | System.out.println("getPersonCount13:" + lunch.getPersonCount13()); |
| | 454 | System.out.println("getPersonCount15:" + lunch.getPersonCount15()); |
| | 455 | } |
| | 456 | } |
| | 457 | |
| | 458 | }}} |
| | 459 | |
| | 460 | 这次Code Kata活动,总体来说,还是比较顺利,中途也出现了一些,代码设计上的分歧意见,和代码设计中发现的问题,但小组成员都虚心倾听别人意见,认真思考 |
| | 461 | 最后讨论统一编程思路,大家都受益良多。[[BR]] |
| | 462 | |
| | 463 | 比如说,开始活动之前,王安宁就发现题目本身存在一些设计不合理的地方,后来经过讨论修改,敲订题目。[[BR]] |
| | 464 | |
| | 465 | 秦鸿源在大家在陷入过度设计陷井的时候,站出来,提出分解问题,各个击破的方案,让大家思路更清晰,更有条理.[[BR]] |
| | 466 | |
| | 467 | 陈阳提出使用队列比使用数组更适合解决打饭排队问题,丁健勇与邝巨桓,在小组成编码过程中给过很多非常不错的经验与建议,[[BR]] |
| | 468 | |
| | 469 | 活动之中还有很多精彩的细节... |