OO第三次博客作业

21201122-温振宇

前言

  • 本次博客任务主要是PTA中的电信类设计的题目(较难)以及其他伴随的三道题目(较易),以及分析前几次的实验题。通过这十几周对java的进一步学习,我对“面向对象”这一编程思想有了更加深入的理解,通过这几次pta大作业和一次期中考试和五次实验,在这十几周中我学会了多态、继承等等面向对象的概念,也意识到了数学和编程是牢牢结合的观念,数学是用于解决现实生活中的问题,而编程可以用来使数学的问题简化,同时也可以大量减少人工计算量,这一点可以通过pta大作业的电信设计的题目得到,而继承等面向对象的概念则可以通过期中考试的三道题得出。所以让我浅浅谈一下这次的心得感悟吧。
  • 电信计费的设计问题,老师巧妙的通过三道题,层层递进的考察了java面向对象的“继承”这一用法,继承首先需要一个“是”(is-a)关系,通过继承,可以极大的减少代码的复用,使代码看上去简洁,便于维护,继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作。在电信计费的计费规则中有集中体现。
    感悟:这次短时间,pta的大题难度有所下降,主要考察了正则表达式以及字符串的 一系列操作,以及集合类型的操作,对字符串的一些方法调用有了新的认识,让我对java语言的类、对象、方法以及属性之间的关系的认知有了新的提升

PTA中的电信计费系列的题目

  • 这次主要考察的是与话费相关的题目,考察了对类图的程序设计,主要考查了集合类型的增删改查,以一开始的座机为例,首先要先开户,也要通过正则表达式来检验开户的输入格式是否正确。
String regex1 = "^u-\\d{4}\\d{7,9} 0";

通过这样的正则表达式就可以判断输入格式是否符合要求了,也便于我们后期进行一行列的操作,如分割字符串提取数据等。
在开完户之后,接下来就是要创建用户了,用户信息包含了许多,如地址、号码等信息,还有通话记录,短信记录,等等所以我是这样设计的

class User {
    private UserRecords userRecords = new UserRecords();
    private double balance = 100;
    private ChargeMode chargeMode;
    private String number;

    public User(String number, ChargeMode chargeMode) {
        this.number = number;
        this.chargeMode = chargeMode;
    }

用户信息通过另外的通话记录类来储存,另外还有计费方式,因为不同的用户可能有不同的套餐,所以要储存计费方式,最后每个用户的余额也要记录下来。
在构造的时候,输入手机号码,以及计费方式就可以构造出一个新的用户了。

通话记录类

刚刚在用户类中储存了一个通话记录类,目的就是记录。
那么我们是如何记录通话记录的呢,首先我们要将传入的信息进行分类,例如将呼叫时间和呼叫区域记录下来,以及通话时间。这样便可设计出一个通话记录类出来,部分代码如下:

class UserRecords {
    private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>();
    private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>();
    private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>();
    private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>();
    private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>();
    private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>();
    private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>();
    private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>();

而现在也到了最重要的环节了,那就是话费的计算,在每一次pta大作业中都有不同的计费方式,但大体是一致的,以座机计费方式为例,月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
那我的方法是每一种区域就对应一个类,以省外为例:

class LandPhoneInCityRule extends CallChargeRule {//座机拨打市内

    public double calCost(ArrayList<CallRecord> callRecords) {
        double cost = 0;
        for (CallRecord callRecord : callRecords) {
            if ((((callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime()) / 1000) % 60) != 0) {
                cost += ((((callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime()) / (60 * 1000)) % 60) + 1) * 0.1;
            } else {
                cost += (((callRecord.getEndTime().getTime() - callRecord.getStartTime().getTime()) / (60 * 1000)) % 60) * 0.1;
            }
        }
        return cost;
    }
}

因为在前期我已经做好了工作,将省内和省外的分开来,进入不同的arraylist中去,这样便于管理一点,像这样

for (int i = 0; i < users.size(); i++) {
                        if (users.get(i).getNumber().equals(split[1])) {//代表主叫
                            if (users.get(i).getNumber().equals(split[2])) {//代表被叫
                                break;
                            }
                            else if (users.get(i).getNumber().substring(0, 5).equals(split[2].substring(0, 5))) {//代表主叫和被叫在市内);
                                users.get(i).getUserRecords().addCallingInCityRecord(callRecord);
                            } else if (callRecord.getAnswerAddressAreaCode().equals("0701") || (callRecord.getAnswerAddressAreaCode().substring(0, 3).equals("079") && callRecord.getAnswerAddressAreaCode().charAt(3) <= '9' && callRecord.getAnswerAddressAreaCode().charAt(3) >= '0')) {
                                users.get(i).getUserRecords().addCallingInProvinceRecord(callRecord);
                            } else {
                                users.get(i).getUserRecords().addCallingInLandRecord(callRecord);
                            }
                        }
                    }
                }

与此同时,对于时间的输入判定,我们可以通过SimpleDateFormat类来进行判断,像这样:

public static boolean validDateTimeSimple(String dateTime) {
        if (dateTime == null) {
            return false;
        }
        DateFormat df = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss yyyy.MM.dd HH:mm:ss");
        df.setLenient(false);//表示严格验证

        try {
            df.parse(dateTime);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }
}

通过预先设定好日期的形式来检查日期是否符合标准,也是一种变相的检验输入吧。
最后我还想提一下对于用户表的排序。因为出于便于管理的原因,我将所有新建的用户都放入了arraylist表中,这样一来在输出的时候就很好进行相关操作了,

for (int i = 0; i < users.size(); i++) {
            for (int j = i + 1; j < users.size(); j++) {
                if (users.get(i).getNumber().equals(users.get(j).getNumber())) {
                    users.remove(j);
                } else if (Long.parseLong(users.get(i).getNumber()) > Long.parseLong(users.get(j).getNumber())) {
                    User temp = users.get(i);
                    users.set(i, users.get(j));
                    users.set(j, temp);
                }
            }
        }

这里使用了remove方法和set方法来进行排序操作。最后输出消费金额以及账户余额即可。

  • 这题目的考察还是有一定的难度的,考察的不再是对部分数据的处理,而是将实际的问题变成了考察题目,考察了我们对于实体类设计,怎样用Java实现具体的功能,对我们的考察有了进一步的提升,在解这两道题目我们最先考虑到的是类的设计方法,怎样设计实体类的功能

改进建议

1.在编写代码的时候注意对象这一概念,因为java语言一切都是源于对象,有的时候你以为在调用不同的东西,其实发现调用的还是一个对象,导致输出不理想。此外还要注意方法、属性的状态,有的方法类型不是public的时候就不能使用,而有的属性是private的时候就要通过构造器来设置。

2.在重复运用一些数据时,不妨抽象出一个简单的类出来,可以使得代码效率大大提升,也提高了代码的可读性。

3.要牢记一些java语言中的一些类的方法,比如double类的parseDouble方法就可以将一个字符串类型的数据转换为double类型的。这样可以大大减少我们去自己编写代码的时间,提高了工作效率。

4.继承的时候注意使用super()来构造对象
5.方法改进,许多需要反复用到的方法,下次可以设计成一个固定的方法,只需要传入特定的参数,不要反复去写一个方法,这样可以简化我们的代码长度。

②圈复杂度改进,每一次循环遍历都会加深圈复杂度,一次次的遍历都会使我们的圈复杂度越来越高,所以在一次遍历的时候尽可能让这次遍历多做一些事情。

总结

在这几次pta练习中中,我学会了很多的新的东西,比如类的继承,类的多态,方法的重载。还有正则表达式,可以使我们判断输入是否符合要求的格式,还学会了string类的很多方法,但是对一些代码算法依旧不太熟悉,导致不能很好的通过测试点。此外我的程序中只有一个主方法,显得过于累赘。在以后的习题集中我会尽量多的使用方法来使代码更加简洁。我还有个建议就是希望老师可以将测试点的提示打开,不然调试起问题就只知道错了而不知道哪里错了,路漫漫其修远兮,吾将上下而求索,希望以后可以继续好好的进行java语言的学习。思考对象的时候,需要采用形象思维,而不是程序化的思维。与程序化设计相比,对象的设计过程更具挑战性——特别是在尝试创建可重复使用(可再生)的对象时”

  • 通过本次题目集也学到了减少代码长度的方法,那就是将一直使用的方法,设计成一个传入特定的参数即可得到结果的,这样我们在遇到需要使用的情况时只需要,调用这个方法即可。

⑤还需要在Java中一些上课没有讲到的类,但用起来很方便的类,需要自己去深入的了解一下,因为这样可以大大的提高了我们的解题效率。

⑥还需要进一步提高自己的编程思维,在解题时提前设计好类之间的关系,类的功能,这样写起来代码很快,效率高。

⑦对于课程建议,希望多出一些将实际的应用问题与Java 学习结合起来的题目集,这样才能更好的提高我们的编码的能力。

posted @ 2022-06-18 02:35  nchu_yuuuu  阅读(48)  评论(0)    收藏  举报