复杂方法的开发-分治策略

软件开发的关键在于应用抽象的概念。
方法抽象是通过将方法的使用和它的实现分离来实现的。
用户在不知道方法是如何实现的情况下,就可以使用方法。
方法的实现细节封装在方法内,对使用该方法的用户来说是隐藏的。这就被称为信息隐藏或者个封装。
如果决定改变方法的实现,但只要不改变方法签名,用户的程序就不会受到影响。
方法的实现对用户隐藏在“黑匣子”中

我们前面编写过一些方法,也使用过一些方法。
我们知道,作为方法的使用者,并不需要知道它们是如何实现的。
方法抽象的概念可以应用于程序的开发过程中。
当编写一个大程序时,可以使用“分治”策略,也成为逐步求精,将大问题分解成为子问题。
子问题又分解成更小、更容易处理的问题。

例如,想要编写方法实现如下图的输入年月,得到月份日历表的程序:


 

 


1、分治策略的首先是分析需求,将需求拆分成各个部分
  1)、接受输入
    public int[] readInput(){...}
  2)打印月历
    public void printMonth(int[] date)
    1))、打印月份头
      public void printHead(int[] date)
    2))、打印月份体
      public void printBody(int[] date)

简单的方法拆分之后,我们先完成部分的代码编写
        public static void main(String[] args) {
		PrintMonth printMonth = new PrintMonth();
		printMonth.printMonthDate();
	}

	public void printMonthDate(){
		int[] date = readInput();
		printDate(date);
	}

	private void printDate(int[] date){
		printHead(date);
		printBody(date);
	}

	private void printHead(int[] date){
		System.out.println("\t\t\t"+ date[0] + "  " + transferMonth(date[1]));
		System.out.println("------------------------------------------------");
		System.out.println("Sun \t Mon \t Tue \t Wed \t Thu \t Fri \t Sat ");
	}

	private String transferMonth(int month){
		switch (month){
			case 0: return "January";
			case 1: return "February";
			case 2: return "March";
			case 3: return "April";
			case 4: return "May";
			case 5: return "June";
			case 6: return "July";
			case 7: return "August";
			case 8: return "September";
			case 9: return "October";
			case 10: return "November";
			case 11: return "December";
			default: return "";
		}
	}

	private void printBody(int[] date){

	}

	private int[] readInput(){
		Scanner sc = new Scanner(System.in);

		int[] date = new int[2];
		System.out.println("请输入完整的年,大于1919:");
		date[0] = sc.nextInt();
		System.out.println("请输入完整的月");
		date[1] = sc.nextInt();
		return date;
	}

  

我们发现,打印月份体代码比较复杂,因此我们先只写了一个空的方法声明,将其他代码部分完成并简单测试,为了不影响程序效果,可以将方法体置空,或者方法体内模拟数据执行。


现在再来分析打印方法体:
  1、打印空格
    public void printSpace(int week)
  2、打印数字
    public void printDayNumber(int week, int monthDay)
  
  打印空格和打印数字需要两个数据:
    1、当月第一天是星期几
      getFirstDayWeek(int year, int month)
    2、本月有多少天
      getMonthDayCount(int month)

对应编写方法与测试:
        private void printBody(int[] date){
		boolean isLeap = isLeapYear(date[0]);
		int firstDayWeek = getFirstDayWeek(date[0], date[1]);
		int monthDayCont = getMonthDayCount(date[1], isLeap);

		printSpace(firstDayWeek);
		printDayNumber(firstDayWeek, monthDayCont);
	}

	private void printSpace(int week){
		for (int i= 0; i< week-2; i++){
			System.out.print("  \t");
		}
	}

	private void printDayNumber(int week, int monthDay){
		int dayStart = 1;
		while(dayStart<monthDay){
			System.out.print(dayStart++ + "\t");
			if ((dayStart+week)%7==2 ){
				System.out.print(dayStart++ + "\t");
				System.out.println();
			}
		}

	}

	private int getFirstDayWeek(int year, int month){
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, month-1);
		calendar.set(Calendar.DAY_OF_MONTH, 1);

		return calendar.get(Calendar.DAY_OF_WEEK);
	}

	private int getMonthDayCount(int month, boolean isLeap){
		switch(month){
			case 1:
			case 3:
			case 5:
			case 7:
			case 12:
				return 31;
			case 2:
				return isLeap? 28 : 29;
			default:
				return 30;
		}
	}

	private boolean isLeapYear(int year){
		boolean item1 = year%4==0;
		boolean item2 = year%400==0;
		boolean item3 = year%100==0;
		if (item1 && (!item3) || item2 ){
			return true;
		}else {
			return false;
		}

	}

  

分治策略,指的就是将问题拆分成为多个子问题,然后挑简单的先完成,这样,就不会出现问题太过复杂而难以下手的情况了。





posted @ 2020-02-05 16:15  guodaxia  阅读(246)  评论(0编辑  收藏  举报