DIY迷你邮件客户端的开发算是告一段落,能够从中获取的东西需要往后实践中去感受和践行了。面对开始出现的问题,没能处理好,只有在整个过程来处理和消化掉可能带来的更多问题。
思考DIY迷你客户端开发手记(一)中的5中问题才是清除掉乱七八糟的工程之后的价值了。
1.业务策略编程
在整个应用中最核心的问题是:通过选择收件人的邮件地址的源文件,加载到收件人的集合中,进而发送相应的邮件。
处理这个问题自然想到了策略模式。
先定义一个接口,声明了子类需要实现的方法,然后通过不同的需求来实现其中的功能。
编码-0:定义了解析文件中的联系人邮件地址的策略接口
1 public interface AnalysisStrategy { 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /** 18 19 20 21 22 23 24 25 * 26 27 28 29 30 31 32 33 * 解析联系人数据源 34 35 36 37 38 39 40 41 * 42 43 44 45 46 47 48 49 * @return list 50 51 52 53 54 55 56 57 */ 58 59 60 61 62 63 64 65 public List<String> analysisSrc(); 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 } 82 83 84 85 86 87 88 89
编码-1:主要的两种模式是,解析Excel文件和XML文件
1 public class ExcelContacts implements AnalysisStrategy { 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private File excelFile; 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public ExcelContacts(File f) { 42 43 44 45 46 47 48 49 this.excelFile = f; 50 51 52 53 54 55 56 57 } 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 /** 74 75 76 77 78 79 80 81 * 联系人Excel表 82 83 84 85 86 87 88 89 * 90 91 92 93 94 95 96 97 * @help 参见规定的Excel格式 98 99 100 101 102 103 104 105 * 106 107 108 109 110 111 112 113 * @return list 114 115 116 117 118 119 120 121 */ 122 123 124 125 126 127 128 129 @Override 130 131 132 133 134 135 136 137 public List<String> analysisSrc() { 138 139 140 141 142 143 144 145 Workbook wb = null; 146 147 148 149 150 151 152 153 List<String> contactsList = null; 154 155 156 157 158 159 160 161 try { 162 163 164 165 166 167 168 169 wb = Workbook.getWorkbook(excelFile); 170 171 172 173 174 175 176 177 Sheet[] sheets = wb.getSheets(); 178 179 180 181 182 183 184 185 contactsList = new ArrayList<String>(); 186 187 188 189 190 191 192 193 for (int i = 0, j = sheets.length; i < j; i++) { 194 195 196 197 198 199 200 201 Cell[] cells = sheets[i].getColumn(2); 202 203 204 205 206 207 208 209 for (int row = 1, rows = cells.length; row < rows; row++) { 210 211 212 213 214 215 216 217 String str=cells[row].getContents().trim(); 218 219 220 221 222 223 224 225 if(MiniMailTool.checkEmail(str)){ 226 227 228 229 230 231 232 233 contactsList.add(str); 234 235 236 237 238 239 240 241 } 242 243 244 245 246 247 248 249 } 250 251 252 253 254 255 256 257 } 258 259 260 261 262 263 264 265 } catch (IOException ex) { 266 267 268 269 270 271 272 273 Logger.getLogger(ExcelContacts.class.getName()).log(Level.SEVERE, null, ex); 274 275 276 277 278 279 280 281 } catch (BiffException ex) { 282 283 284 285 286 287 288 289 Logger.getLogger(ExcelContacts.class.getName()).log(Level.SEVERE, null, ex); 290 291 292 293 294 295 296 297 } 298 299 300 301 302 303 304 305 return contactsList; 306 307 308 309 310 311 312 313 } 314 315 316 317 318 319 320 321 } 322 323 324 325 326 327 328 329 //-----------------------------------------------------// 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 public class XMLContacts implements AnalysisStrategy { 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 private File xmlFile; 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 public XMLContacts(File f) { 378 379 380 381 382 383 384 385 this.xmlFile=f; 386 387 388 389 390 391 392 393 } 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 /** 410 411 412 413 414 415 416 417 * 联系人XML表 418 419 420 421 422 423 424 425 * 426 427 428 429 430 431 432 433 * @help 参见规定的XML格式 434 435 436 437 438 439 440 441 * 442 443 444 445 446 447 448 449 * @param xmlFile 450 451 452 453 454 455 456 457 * @return list 458 459 460 461 462 463 464 465 */ 466 467 468 469 470 471 472 473 @Override 474 475 476 477 478 479 480 481 public List<String> analysisSrc() { 482 483 484 485 486 487 488 489 List<String> contactsList=null; 490 491 492 493 494 495 496 497 try { 498 499 500 501 502 503 504 505 SAXBuilder sb =new SAXBuilder(); 506 507 508 509 510 511 512 513 Document doc=sb.build(xmlFile); 514 515 516 517 518 519 520 521 Element root=doc.getRootElement(); 522 523 524 525 526 527 528 529 List<Element> userList=root.getChildren("user"); 530 531 532 533 534 535 536 537 contactsList=new ArrayList<String>(); 538 539 540 541 542 543 544 545 for(int i=0, j=userList.size(); i<j; i++){ 546 547 548 549 550 551 552 553 Element children=userList.get(i); 554 555 556 557 558 559 560 561 String str=children.getChildText("email").trim(); 562 563 564 565 566 567 568 569 if(MiniMailTool.checkEmail(str)){ 570 571 572 573 574 575 576 577 contactsList.add(str); 578 579 580 581 582 583 584 585 } 586 587 588 589 590 591 592 593 } 594 595 596 597 598 599 600 601 } catch (JDOMException ex) { 602 603 604 605 606 607 608 609 Logger.getLogger(XMLContacts.class.getName()).log(Level.SEVERE, null, ex); 610 611 612 613 614 615 616 617 } catch (IOException ex) { 618 619 620 621 622 623 624 625 Logger.getLogger(XMLContacts.class.getName()).log(Level.SEVERE, null, ex); 626 627 628 629 630 631 632 633 } 634 635 636 637 638 639 640 641 return contactsList; 642 643 644 645 646 647 648 649 } 650 651 652 653 654 655 656 657 } 658 659 660 661 662 663 664 665
通过这样的方式就可以将不同的文件的解析联系人的过程封装掉,对于调用者来讲是相同的,只需要面向接口编程就可以了。
这里给出源文件的格式:
EXCEL表的格式
XML格式:
这里的格式可以按照已经约定的方式书写,当然亦可以自定义格式,这样就应该编写实现
**AnalysisStrategy(联系人解析)**接口。
2.处理一些关于字符串,邮件地址验证,获取收件人地址信息
这样的问题一般在编程开始的时候会有所考虑,倒是带来的后续问题不大,如何有效的编写更加通用的代码,才是问题的关键。
这里有个关于工具类的命名问题,比如:Utils,Tools,Helper等类的命名都是非常不可取的方式,命名要简明思议,并且能够传单一定的信息,像这个工具类处理哪方面的问题,都应该能够很好的放映出来。
工具类有可能涉及到:字符串处理方面;文件解析,文件过滤方面;图形用户界面编程中的组件信息处理方面;特定的多出使用的方法,变量等;类的构造和管理等方面。
这个应用程序设计的相关方法不是很多,较好的处理掉了。
编码-2:邮件客户端程序的工具类
1 /** 2 3 4 5 6 7 8 9 * 10 11 12 13 14 15 16 17 * 邮件客户端程序工具类 18 19 20 21 22 23 24 25 * 26 27 28 29 30 31 32 33 * @author aiilive 34 35 36 37 38 39 40 41 */ 42 43 44 45 46 47 48 49 public final class MiniMailTool { 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 /** 66 67 68 69 70 71 72 73 * 获取框架在Windows中显示的中心点 74 75 76 77 78 79 80 81 * 82 83 84 85 86 87 88 89 * @param jf 90 91 92 93 94 95 96 97 * @return 中心点 98 99 100 101 102 103 104 105 */ 106 107 108 109 110 111 112 113 public static Point getCenter(JFrame jf) { 114 115 116 117 118 119 120 121 Point p = new Point(); 122 123 124 125 126 127 128 129 Dimension dim = jf.getSize(); 130 131 132 133 134 135 136 137 int width = dim.width; 138 139 140 141 142 143 144 145 int height = dim.height; 146 147 148 149 150 151 152 153 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 154 155 156 157 158 159 160 161 p.setLocation((screenSize.width - width) / 2, ((screenSize.height - height) / 2)); 162 163 164 165 166 167 168 169 return p; 170 171 172 173 174 175 176 177 } 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 /** 194 195 196 197 198 199 200 201 * 通过收件人信息获取收件人 202 203 204 205 206 207 208 209 * 210 211 212 213 214 215 216 217 * @param contactsString 218 219 220 221 222 223 224 225 * @return List 226 227 228 229 230 231 232 233 */ 234 235 236 237 238 239 240 241 public static List getToContacts(String contactsText) { 242 243 244 245 246 247 248 249 String[] contacts = contactsText.split(";"); 250 251 252 253 254 255 256 257 return Arrays.asList(contacts); 258 259 260 261 262 263 264 265 } 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 /** 282 283 284 285 286 287 288 289 * 验证输入的联系人的电子邮箱的有效性 290 291 292 293 294 295 296 297 * 298 299 300 301 302 303 304 305 * @param contactsText 306 307 308 309 310 311 312 313 * @return bo 314 315 316 317 318 319 320 321 */ 322 323 324 325 326 327 328 329 public static boolean checkContacts(String contactsText){ 330 331 332 333 334 335 336 337 String[] contacts = contactsText.split(";"); 338 339 340 341 342 343 344 345 boolean bo=true; 346 347 348 349 350 351 352 353 for (int i = 0; i < contacts.length; i++) { 354 355 356 357 358 359 360 361 contacts[i] = contacts[i].trim(); 362 363 364 365 366 367 368 369 if(!checkEmail(contacts[i])){ 370 371 372 373 374 375 376 377 bo=false; 378 379 380 381 382 383 384 385 break; 386 387 388 389 390 391 392 393 } 394 395 396 397 398 399 400 401 } 402 403 404 405 406 407 408 409 return bo; 410 411 412 413 414 415 416 417 } 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 /** 434 435 436 437 438 439 440 441 * 中文字符转换 442 443 444 445 446 447 448 449 * 450 451 452 453 454 455 456 457 * @param str 458 459 460 461 462 463 464 465 * @return strEncode 466 467 468 469 470 471 472 473 */ 474 475 476 477 478 479 480 481 public static String chineseEncode(String str) { 482 483 484 485 486 487 488 489 String strEncode = str; 490 491 492 493 494 495 496 497 try { 498 499 500 501 502 503 504 505 byte[] bts = str.getBytes("ISO-8859-1"); 506 507 508 509 510 511 512 513 strEncode = new String(bts, "GB2312"); 514 515 516 517 518 519 520 521 } catch (UnsupportedEncodingException ex) { 522 523 524 525 526 527 528 529 Logger.getLogger(MiniMailTool.class.getName()).log(Level.SEVERE, null, ex); 530 531 532 533 534 535 536 537 } 538 539 540 541 542 543 544 545 return strEncode; 546 547 548 549 550 551 552 553 } 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 /** 570 571 572 573 574 575 576 577 * 将字符数组char [] 转化为字符串String 578 579 580 581 582 583 584 585 * 586 587 588 589 590 591 592 593 * @param ch [] 594 595 596 597 598 599 600 601 * @return String 602 603 604 605 606 607 608 609 */ 610 611 612 613 614 615 616 617 public static String arrayToString(char[] ch) { 618 619 620 621 622 623 624 625 if (ch == null) { 626 627 628 629 630 631 632 633 return "null"; 634 635 636 637 638 639 640 641 } 642 643 644 645 646 647 648 649 StringBuilder b = new StringBuilder(); 650 651 652 653 654 655 656 657 for (int i = 0; i < ch.length; i++) { 658 659 660 661 662 663 664 665 b.append(ch[i]); 666 667 668 669 670 671 672 673 } 674 675 676 677 678 679 680 681 return b.toString(); 682 683 684 685 686 687 688 689 } 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 /** 706 707 708 709 710 711 712 713 * 验证电子邮件地址是否有效 714 715 716 717 718 719 720 721 * 722 723 724 725 726 727 728 729 * @param email 电子邮件地址字符串 730 731 732 733 734 735 736 737 * @return 布尔值 738 739 740 741 742 743 744 745 */ 746 747 748 749 750 751 752 753 public static boolean checkEmail(String email) { 754 755 756 757 758 759 760 761 Pattern pattern=Pattern.compile("\\w+@(\\w+.)+[a-z]{2,3}"); 762 763 764 765 766 767 768 769 Matcher matcher=pattern.matcher(email); 770 771 772 773 774 775 776 777 return matcher.matches(); 778 779 780 781 782 783 784 785 } 786 787 788 789 790 791 792 793 } 794 795 796 797 798 799 800 801
上面的代码涉及到了用户界面组件的工具类方法,字符串处理,常用的验证等。对于一个较大的工程,或者是涉及相关的操作非常多和复杂的时候,就得考虑方法的组织,重构,提取,建立更好的类的层次关系这样才符合面向对象编程基本思想,才能够获得可以水平和垂直扩展的机会。同时使得代码的耦合度降到最低,想要达到如此美好的境况,又得回到设计和组织方面去。
3**.用户界面的布局,各个组件在特定时间的状态**
正因为有用户界面,所以考虑各组件之间的组织关系,程序运行是组件的状态。活动图虽然集中注意力的面向的是活动参与者,对于桌面应用程序而言,每一个组件正可以看作是活动的参与者,因此正确对待组件状态,就可以呈现一个真实的活动状态。
比如:在没有进行邮件信息检查时,发送按钮是禁用的;为发送邮件时,状态信息显示填写发件信息,发送完成时发送完成或者发送失败;验证收件人的电子邮件信息时;不符合格式的地址,显示相应的提示信息等等,这样都源于我们对客观的事物和感知,也是对我们的用户交互,人性化设计的要求。
本文出自 “野马红尘” 博客,谢绝转载!

