OO四到六次作业总结
一、前言
这是我学习java的第二个月,这三次的题目集难度没什么变化,但是题量也明显增加了。在这三次题目集中学习了聚合、封装、继承、多态、接口、正则表达式等等。虽然新知识比较好学,但正则表达式这块感觉有点问题,可能是自己方法没有掌握或是解题思路不够清晰,这三次题目集中两到正则表达式的题目感觉没什么思路。
二、设计与分析
1、两种日期类聚合设计的优劣比较
在题目集4(7-2)、题目集5(7-4)中,都是用聚合设计来写的日期类题目。相比于前者,后者的设计可拓展性更强,具有较强的可延伸性。题目集4的类通过连续调用来实现功能的,DateUtil类调用Date类,Date类调用Day类,Date类调用Day类,Day类调用Month类,Month类调用Year,过程过于繁琐,而且如果出错了或者加一些别的东西都非常麻烦,需要从头去找。
而题目集5中运用多个继承一个的特点可以更加快速的运用父类,而且简洁明了了很多,而且如果出错了或者加一些别的东西都非常容易,找一个就行了。
两题类图对比如下:
7-2:

7-5:

由此可看出题目集五全继承一个类,显得更加简洁。
2、三种渐进式图形
在题目集4(7-3)、题目集6(7-5、7-6)中
题目集4(7-3):


这是一个关于继承的题目,“类Shape,无属性,有一个返回0.0的求图形面积的公有方法public double getArea();”这是父类。类Circle,类Rectangle,类Ball,类Box都要继承它,因为每个子类都要用到求面积这个功能。
由此可以推测出,当每个类都要运用同一个方法时,可以把它们提取出来,做成父类,让其他的来继承这个父类,可以使代码更加简洁明了,而且出错时更好改正。
题目集6(7-5):


本题运用了继承和多态
题目集6(7-6):


本题用了接口。
封装:是面向对象的特征之一,是对象和类概念的主要特性。
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承:是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。继承概念的实现方式有三类:实现继承、接口继承和可视继承。
使用继承可以有效实现代码复用,避免重复代码的出现。
多态:是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
可以增强程序的可扩展性及可维护性,使代码更加简洁。不但能减少编码的工作量,也能大大提高程序的可维护性及可扩展性。
3、正则表达式技术的分析总结
(1)正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。它是一种有价值的基础工具,可以用于很多类型的文本处理, 如匹配,搜索,提取和分析结构化内容。
(2)、在java中,通过适当命名的Pattern类可以容易确定String是否匹配某种模式。模式可以象匹配某个特定的String那样简单,也可以很复杂,需要采用分组和字符类,如空白,数字,字母或控制符。
(3)、一些简单的字符类:
\d 数字
\D 非数字
\w 单字字符(0-9,A-Z,a-z)
\W 非单字字符
\s 空白(空格符,换行符,回车符,制表符)
\S 非空白
[] 由方括号内的一个字符列表创建的自定义字符类
. 匹配任何单个字符
下面的字符将用于控制将一个子模式应用到匹配次数的过程.
? 重复前面的子模式0次到一次
* 重复前面的子模式0次或多次
+ 重复前面的子模式一次到多次
(4)、正则表达式可以处理庞大的数据,如题目集5中的水文数据处理就需要能够非常熟练地运用正则表达式,才能去匹配,去分割。而像题目集六中的前几道题,就比较简单了,只需要匹配简单的QQ号,电话号码之类的。
(5)、当我们能熟练地运用正则表达式时,就可以做爬虫,去网页上获取自己想要的东西。
4、在题目集5(7-4)中Java集合框架应用的分析总结
集合框架:用于存储数据的容器。
集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。
任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
接口:表示集合的抽象数据类型。接口允许我们操作集合时不必关注具体实现,从而达到“多态”。在面向对象编程语言中,接口通常用来形成规范。
实现:集合接口的具体实现,是重用性很高的数据结构。
算法:在一个实现了某个集合框架中的接口的对象身上完成某种有用的计算的方法,例如查找、排序等。这些算法通常是多态的,因为相同的方法可以在同一个接口被多个类实现时有不同的表现。事实上,算法是可复用的函数。
它减少了程序设计的辛劳。
特点:
1、对象封装数据,对象多了也需要存储。集合用于存储对象。
2、对象的个数确定可以使用数组,对象的个数不确定的可以用集合。因为集合是可变长度的。
集合框架通过提供有用的数据结构和算法使你能集中注意力于你的程序的重要部分上,而不是为了让程序能正常运转而将注意力于低层设计上。
通过这些在无关API之间的简易的互用性,使你免除了为改编对象或转换代码以便联合这些API而去写大量的代码。它提高了程序速度和质量。
好处:
1、容量自增长;
2、提供了高性能的数据结构和算法,使编码更轻松,提高了程序速度和质量;
3、允许不同 API 之间的互操作,API之间可以来回传递集合;
4、可以方便地扩展或改写集合,提高代码复用性和可操作性。
5、通过使用JDK自带的集合类,可以降低代码维护和学习新API成本。
三、采坑心得
对于我来说日期类的题目有较大的问题,前面两个题目集的日期问题面向对象设计都没有全对,总是在求两日期相差天数上写不对。
像:
public boolean equalTwoDates(DateUtil date) {
if(year.getValue()==date.year.getValue()&&month.getValue()==date.month.getValue()&&day.getValue()==date.day.getValue())
return true;
else
return false;
}
public int getDaysofDates (DateUtil date) {
int t = 0,a=0;
if(equalTwoDates(date)) {
}
else if(compareDates(date)) {
while(this.showDate() != date.getNextNDays(a).showDate()) {
a ++;
}
t = a;
}
else {
while(this.showDate() != date.getPreviousNDays(a).showDate()) {
a ++;
}
t = a;
}
return t;
}
public String showDate() {
return year.getValue()+"-"+month.getValue()+"-"+day.getValue();
}
按上面的代码可以单独求出两日期相差天数,但放在所以代码上时就不行了,经过多位大佬的帮助下,还是没成功,感觉要废了。
还有就是水文处理题目集有较大的疑问和困难,对于正则表达式的题目,感觉莫名的难写。首先要通过正则表达式分割每行输入的数据,再对每行数据分块处理。
代码:
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main{
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
/*String regex="([1-9]\\d{0,3}/([1-9])|1[0-2])/(([1-9])|([1-2]\\d)|(3[0-1]))\\s([02468])|1([02468])|(2[02]):00\\|"
+ "(([1-9]\\d{0,2})|1000)([\\.\\d{0,3}])?\\|(([1-9]\\d{0,2})|1000)([\\.\\d{0,3}])?\\|"
+ "([1-9]\\.\\d{2})/([1-9]\\.\\d{2})\\|"+"(([1-9]\\d{0,2})|1000)([\\.\\d{0,3}])?";*/
String regex1="([1-9]\\d{0,3})/(([1-9])|(1[0-2]))/(([1-9])|([1-2]\\d)|(3[0-1])) (([02468])|(1[02468])|(2[02])|0):00";
String regex2="[1-9]\\d{0,2}(\\.\\d{0,3})?";
String regex3="[1-9]\\d{0,2}(\\.\\d{0,3})?";
String regex4="([1-9]\\.\\d{2})/([1-9]\\.\\d{2})";
String regex6="[1-9]\\.\\d{2}";
String regex5="[1-9]\\d{0,2}(\\.\\d{0,3})?";
String regex="(\\s)+";
int i=0,cnt=0,cnt1=0;
String []row=new String[1000];
String []s=new String[1000];
String []a=new String[1000];
String []data=new String[100];
char []c=new char[1000];
double max=0;
int h=0;
int g[]=new int[10];
//System.out.println();
row[i]=input.nextLine();
while(!row[i].equals("exit")) {//字符串数组获取每行的输入
i++;
row[i]=input.nextLine();
}
boolean bl=Pattern.matches(regex,row[0]);
if(row[0].equals("exit")||bl==true||(row[0].equals(""))) {//无输入
System.out.println("Max Actual Water Level:0.00");
System.out.println("Total Water Flow:0.00");
}
else {
for(int j=0;j<i;j++) {
row[j]=row[j].trim();
cnt=0;
for(int k=0;k<row[j].length();k++) {
c[k]= row[j].charAt(k);
s[k]=c[k]+"";
if(s[k].equals("|"))
cnt++;
}
if(cnt==4) {
data=row[j].split("\\|");//将每行数据分割成五部分
boolean bl1=Pattern.matches(regex1,data[0]);
boolean bl2=Pattern.matches(regex2,data[1]);
boolean bl3=Pattern.matches(regex3,data[2]);
boolean bl4=Pattern.matches(regex4,data[3]);
boolean bl5=Pattern.matches(regex5,data[4]);
//boolean bl6=Pattern.matches(regex6,row[j]);
if(bl1==true) {
/*Pattern pattern = Pattern.compile(regex2);
Matcher matcher=pattern.matcher(row[j]);*/
}
else {
System.out.printf("Row:%d,Column:1Wrong Format\n",j+1);
}
if(bl2==true) {
}
else {
System.out.printf("Row:%d,Column:2Wrong Format\n",j+1);
}
if(bl3==true) {
}
else {
System.out.printf("Row:%d,Column:3Wrong Format\n",j+1);
}
if(bl4==true) {
}
else {
//double []b=new double[10];
String []e=new String[100];
e=data[3].split("/");
boolean bl6=Pattern.matches(regex6,e[0]);
if(bl6==false)
System.out.println("Row:"+(j+1)+",Column:4Wrong Format");
boolean bl7=Pattern.matches(regex6,e[1]);
if(bl7==false)
System.out.println("Row:"+(j+1)+",Column:5Wrong Format");
}
if(bl1==bl2==bl3==bl4==bl5==true)
{
double []b=new double[10];
a=data[3].split("/");
b[0]=Double.parseDouble(a[0]);
b[1]=Double.parseDouble(a[1]);
for(h=0;h<i;h++)
if(b[1]>b[0]) {
g[h]=j+1;
//System.out.printf("Row:%d GateOpening Warning",j+1);
}
cnt1++;
}
if(bl5==true) {
//double max=0;
double level[]=new double[10];
level[j]=Double.parseDouble(data[4]);
if(max<level[j])
max=level[j];
// System.out.println("Max Actual Level:"+max);
}
else {
System.out.println("Row:"+(j+1)+",Column:6Wrong Format");
}
if(bl1==false||bl2==false||bl3==false||bl4==false||bl5==false)
System.out.println("Data:"+row[j]);
if(cnt1==i) {
System.out.print(cnt1);
for( h=0;h<i;h++)
System.out.printf("Row:%d GateOpening Warning\n",g[h]);
System.out.println("Max Actual Level:"+max);
}
}
else {
System.out.println("Wrong Format");
System.out.println(row[j]);
}
}
}
}
我就一直卡在输出语句的规范问题上,我会在以后更加认真学习正则表达式,争取下一个正则表达式的难题能够写完,并过关。
四、改进建议
1、在这么多次pta作业中发现自己写的代码圈复杂度较高,所以在以后的代码中我会尽可能少用for循环和if语句,若是if和for嵌套的话,圈复杂度会加倍增长,这会显得我们的代码非常繁琐。如输出数组时可以不用for循环,用foreach循环或直接输出数组都是可行的方案。
2、当每个类都要运用同一个方法时,可以把它们提取出来,做成父类,让其他的来继承这个父类,可以使代码更加简洁明了,而且出错时更好改正。要更加熟练地掌握封装、继承、多态、接口。
3、接口和抽象类都可以用为对象指定共同的行为,接口比抽象类更加灵活。
4、要多运用面向对象的七大原则。
开闭原则(Open-Closed Principle,OCP)
里氏替换原则(Liskov Substitution Principle,LSP)
依赖倒转原则(Dependence Inversion Principle,DIP)
合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)
迪米特法则(Law of Demeter,LoD或LKP(Least Knowledge Principle))
接口隔离原则(Interface Segregation Principle,ISP)
单一职责原则(Single Response Principle,SRP)
五、总结
通过这三次题目集的训练,让我学会了封装、继承、多态、接口这几大方法,感觉自己能够写出更加好的更加长的代码了。还学到了一些比较好的设计模式,并体会到了这些设计模式给面向对象程序设计带来的好处(耦合性低,可扩展性强,代码复用性高等)。还让我学会了一些正则表达式,虽然我的正则表达式不太好但我以后会认真学下去的。
我觉得自己应该更加努力的学习java,自学能力有待提高,而且要在老师讲课之前先预习一下,这样可以让我更快跟上课程节奏,更好的学习。
虽然这次的三个题目集没写好,但我会继续努力学习的,争取赶上第一梯队。
20201224-徐建强
浙公网安备 33010602011771号