OO第三次Blog

2021/6/9 10:21:14

本文主要是介绍OO第三次Blog,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、前言—关于这次面向对象的实现

这次,我又来写我的blog啦!这几次的实验可以说已经开始考察面向对象的思考这个环节了,已经不再是简简单单的敲写语法相关的基本知识了,更多的是我们在对代码的思考这一过程吧。这三次的作业难度方面中等,其实考察的并不是很难,这几次更加注重的是我们对于面向对象的思考。

对于7-1来说,考察的主要是掌握类的继承、多态性使用方法以及接口的应用,这其实在Java面向对象编程这一过程还是非常的重要的。正如我们都知道面向对象的三大特征是封装,继承,多态。而对于7-1与7-2这两次的题目主要就是进行了多态的考察,还是非常有助于我们更好的理解Java的特点以及好处的。而在第八次的作业中,就难度明显上升了,考察的就更加全面了。这次让我们设计一个ATM 机的模拟程序,能够完成用户的存款、取款以及查询余额功能,并且在这次的实验中,并没有帮我们设计好类图关系,所以的思考设计都需要我们独立完成,这就大大提升了一个档次。考察的知识可以说是非常的全面了,需要我们很好的利用Java的各个特点才能使得设计出来的程序有很好的复用性。在第九次实验中就是在第八次的实验基础上增加了透支功能与跨行存取操作,考察的知识点也是很全面的,并且若是上次的设计不好,那么这次的设计或许就无法利用上次的了。

总的来说,这几次的实验难度并不会很大,更多的是考察了我们对面向对象编程这一思想,只有很好的理解了这一思想,才能很好的将这几次的代码做到(beautiful)的境界(虽然目前对于我们来说非常的困难吧!),或许多code可以更好的理解计算机思考的过程吧。

二、关于 Myself 的 design

1. 对于题目集7-1来说,这次的操作主要还是对类的继承以及多态的使用和接口的应用。通过对设计好的类进行操作,在难度方面还是有很大的降低了。我们需要正确的理解类与类之间的关系便可以很好的将这次的作业完成了。这次实际上就是对图形进行分类和计算出各个图形的面积并进行排序。设计上来说,主要就是设计了几个类,包括DealCardList类,Card类,Shape类,Circle类,Rectangle类,Triangle类,Trapezoid类,通过对这几个类进行操作,即可将输入的数据进行正确的处理。

 

通过类图我们就可以发现,这几个图形通过继承Shape类便可以很好的将这些图形分开,同时他们又都属于图形,这样以来就很好理解了。而Shape类又以来Card类,Card类依赖DealCardList类,最终可以说是依靠DealCardList类来将这一个个数据进行分类处理了,在main函数自然而然也就变得简单了,而这一个个类就负责自己需要做的事情就可以了,类与类之间的事务就不会错综复杂(让人头脑不清)了,而这一设计又很好的体现了Java的单一职责原则(好处:可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;提高类的可读性,提高系统的可维护性;)了。在7-2中其实也就是增加了,这些,如右图:

 

其实说到底就是在7-1的基础上进行修改下即可。我们在上一题是就考虑到了不同的图形,而不同的图形就有它们对应的名称,我们可以在DealCardList类里面的showResult方法进行下分类操作即可,我们通过获取每个图形的名称利用equals方法判断图形的形状分类存入不同的图形的ArrayList里面即可(我是创建了不同图形的ArrayList来存储,这样子可能有点不好吧,感觉有点太过浪费空间资源了,但是我也没有想到什么好的方法)。

这样子越看感觉越low。这两道都可以说是一个题目,主要还是看我们有没有正确理解这类与类之间的关系了。

2. 对于题目集8来说,这确实是一次挑战,刚拿到题目我就在想这次的题目应该不是很难(我以为还是像以前一样,老师帮我们设计好了类图),但是,当我打开指导书,我懵了。

这次没有类图,所有的东西都需要我们自己来设计。说实话,刚拿到手感觉还是有点不会设计,但是经过了几天了思考是,对ATM机的设计有了一定的想法。现在就来谈谈我的想法吧。

首先,中国银联肯定是可以说是可以操作任何东西的,所以在设计上我是将中国银联的地位默许成最高了。我是将中国银联里面放了银行,通过getter和setter方法来获取设置银行,然后通过银行来操作后续的业务等等。

 

 银行是拥有自己的ATM机的,并且拥有所以的账户,卡,以及自己的用户的,用户可以知道自己在哪家银行开户,一个账户拥有多张卡,每张卡有自己的卡号。而我们在进行操作时就可以通过银行来判断自己十分拥有这个用户,用户获取自己的账户,账户再来获取账户里面的卡,这样子就实现了各种信息的对应与获取,同时也算是比较符合现实生活。同时我创建了一个InitialData类来初始化所有的数据,同时创建了一个DealDate类来进行各种业务的操作,最终的设计类图也就是大概这样子吧,

 

 可能设计的并不好,但是这毕竟经过了自己的思考做出来的,自己也就心满意足了。

后来老师在下一次的作业中发出了自己的代码,让我惊叹不已,老师发出的类图如下:

 

 我理解了下老师的思路,发现有许多的地方是非常的巧妙的,例如在单一职责原则这里,withDraw类就只是单纯的存取款以及数据不合法的输出结束程序。这样就不会在一个类里面还要判断去寻找各个用户,账户,卡之间的对应关系了,看起来就十分的舒适。还有一个让我感觉特别惊叹的地方就是这里:

通过这里

 

判断是否存取设置flag完美的解决了是否存款还是取款,代码就不会显得冗余,而我的就是存取款完全设置了两个方法,使得在判断卡号等操作时运行起来就十分的复杂了。通过这里,我学到了一个非常好的方法来操作某些类似的行为,大大简化代码,提高代码的复用性。

3. 题目集9我是直接利用了老师的代码的基础上修改等,思考了下就将其完成了。在这里我是真正体会到了我们如果一开始就设计好一个结构,那么以后如果想去增加内容等将变得十分的快速。在这里我体会到了设计才是面向对象真正难的地方,而这里我查询了相关的东西,了解到了设计模式代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。所谓设计模式,就是一套被反复使用的代码设计经验的总结(情境中一个问题经过证实的一个解决方案)。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使人们可以更加简单方便的复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。

 

一个优秀的代码往往是由上图这些来构造,使得代码有了更好的使用。

 三、入坑心得与收获

总的来说,这三次的题目集都并没有什么很难过的测试点,题目的难度也还好,没有什么让人感觉很奇怪的测试数据,经过不断的完善,最后所有的测试点都过啦。

• 就7-1题目集来说吧,已经给出了类图了,就是要将类图里面的各种信息读懂,也就自然而然就过了,不过有个地方还是要注意的,在判断圆的半径是要大于0,而不是大于等于0(但是其他图形都是大于等于0,表示疑惑),不然的话

这个测试点就无法通过了。

public boolean validate() {
        return this.radius > 0;
    }

这里改成了大于等于0就过了,表示无奈。

• 对于7-2来说,就是在7-1的基础上修改下和增加点内容,虽然说起来简单,但是在操作起来似乎并没有那么的轻松哦。我当时想到的就是将不同的图形存入不同的ArrayList里面去这样就可以直接输出了,不过在输出方面我还做了一件非常搞笑的事情,看看代码就知晓了:

System.out.print("[");
        for (Card card : cardArrayList) {
            System.out.print(card.getShape().getShapeName() + ":" + String.format("%.2f", card.getShape().getArea()) + " ");
        }
        System.out.print("]");
        System.out.println();
        System.out.println("The Separated List:");
        System.out.print("[");
        for (Double aDouble : circleList) {
            System.out.print("Circle:" + String.format("%.2f", aDouble) + " ");
        }
        System.out.print("]");
        System.out.print("[");
        for (Double aDouble : rectangleList) {
            System.out.print("Rectangle:" + String.format("%.2f", aDouble) + " ");
        }
        System.out.print("]");
        System.out.print("[");
        for (Double aDouble : triangleList) {
            System.out.print("Triangle:" + String.format("%.2f", aDouble) + " ");
        }
        System.out.print("]");
        System.out.print("[");
        for (Double aDouble : trapezoidList) {
            System.out.print("Trapezoid:" + String.format("%.2f", aDouble) + " ");
        }
        System.out.print("]");

看完是否表示非常的可笑,当时没有想到原来Java是那么的强大,完全不需要我自己来输出[ ]这个符号,不过经过的这次我也就自然记住了(正所谓:吃一堑,长一智)。主要增加的代码和修改自然也就是这一块。不过还有一个很大的不足是我没有很好的运用Comparable、Comparator 接口的应用,导致在寻找最大值时代码显得非常的复杂,

 if (maxArea < sumCircleArea) {
            maxArea = sumCircleArea;
        }
        if (maxArea < sumRectangleArea) {
            maxArea = sumRectangleArea;
        }
        if (maxArea < sumTrapezoidArea) {
            maxArea = sumTrapezoidArea;
        }
        if (maxArea < sumTriangleArea) {
            maxArea = sumTriangleArea;
        }
        for (Card card : cardArrayList) {
            if (maxArea < card.getShape().getArea()) {
                maxArea = card.getShape().getArea();
            }
        }

其实前面还有求各个图形面积最大值的遍历(┭┮﹏┭┮),后来思考了下发现如果很好的利用了Collections.max(arrayList);这将很好的简化代码。看来还是需要多了解Java里面自带的一些非常好的方法。

• 在题目集8来说难度就是明显的上升了,这次是需要自己来设计。我的设计也就是在上文的设计提到了,但是我感觉我的代码十分的复杂,尤其是在存取款这一块,例如:

public void WithDrawAndSaveMoney(String string) {
        String[] strings = string.split("\\s+");
        for (int i = 0; i < initializationData.getBanks().size(); i++) {
            for (int j = 0; j < initializationData.getBanks().get(i).getUsers().size(); j++) {
                for (int k = 0; k < initializationData.getBanks().get(i).getUsers().get(j).getAccounts().size(); k++) {
                    for (int t = 0; t < initializationData.getBanks().get(i).getUsers().get(j).getAccounts().get(k).getCards().size(); t++) {
                        if (initializationData.getBanks().get(i).getUsers().get(j).getAccounts().get(k).getCards().get(t).getBankCardNumber().equals(strings[0])) {
                            initializationData.getBanks().get(i).getUsers().get(j).getAccounts().get(k).setInitialBalance(initializationData.getBanks().get(i).getUsers().get(j).getAccounts().get(k).getInitialBalance() - Double.parseDouble(strings[3]));
                            boolean flag = true;
                            if (initializationData.getBanks().get(i).getUsers().get(j).getAccounts().get(k).getInitialBalance() < 0) {
                                flag = false;
                                System.out.println("Sorry,your account balance is insufficient.");
                            }
                            if (flag) {
                                if (Double.parseDouble(strings[3]) < 0) {
                                    System.out.print(initializationData.getBanks().get(i).getUsers().get(j).getUserName() + "在" + initializationData.getBanks().get(i).getBankType() + "的" + strings[2] + "号ATM机上存款¥");
                                } else {
                                    System.out.print(initializationData.getBanks().get(i).getUsers().get(j).getUserName() + "在" + initializationData.getBanks().get(i).getBankType() + "的" + strings[2] + "号ATM机上取款¥");
                                }
                                System.out.printf("%.2f\n", Math.abs(Double.parseDouble(strings[3])));
                                System.out.printf("当前余额为¥%.2f\n", initializationData.getBanks().get(i).getUsers().get(j).getAccounts().get(k).getInitialBalance());
                                break;
                            }
                        }
                    }
                }
            }
        }
    }

这么一看是不是明显有很大一部分来说就是完全重复了,再来看这份代码:

 public void showResult(Account account,int flag) {
        String type = "";
        if(flag == 1) {
            type = "取款";
        }else {
            type = "存款";
            amount *= -1;
        }
        String userName = account.getUser().getName();
        String bankName = account.getBank().getBankName();
        System.out.println(userName + "在" +
                bankName + "的" + ATMID + "号ATM机上" + type + String.format("¥%.2f", amount));
        System.out.println("当前余额为" + String.format("¥%.2f", account.getBalance()));
    }

两个一比较明显就体现出来了差距了。不过虽然我的设计还需要改进,但是就是这样我也遇到了许多的麻烦,例如没有想到

导致我许多的测试点无法通过,不过最后在每个判断输入有误后面加了(插入System。Out代码),最终都通过了。在这题来说,题目难度并没有很大,最大的难度还是面向对象设计这方面,总的来说也就是这张图片吧:

 

 这虽然看起来简单,但是这其中的奥秘还需要我们不断的去探索(当然,如果你天赋异禀那就除外)。在题目集9来说,这里老师给予了我们上一题(题目集8)的源码,这题说到底其实就是在上一题的基础上来修改,毕竟你看题目要求:

 

 似乎好像可以说还少了存款,但是实际上多了可以透支以及跨行取款收取手续费的操作

 

不过在上一题正确答案的基础上修改还是大大降低了难度的。由于正确答案设计的太过完美(作为Java初学者,这是我真心这么觉得),我只需先添加一些增加的用户,银行,账户,卡等等,然后在判断跨行那里修改下就可以了。这里最大的坑就是我们都会认为最大透支50000,那么由于手续费我们是不是取不出来50000,实则不是这样。这里透支50000,就是可以实打实的取出50000,不过因为要手续费,你要欠银行五万多而已(感觉银行好赚啊)。另一个坑就是当我们跨行存取是,收取的手续费由 ATM 机隶属银行决定,这个我还以为是你的卡所隶属的那个银行决定(可能生活经验少了),这里一开始错了,不过发现的早,并没有耽误什么实时间。还有一个我不理解的地方就是当你需要取的钱大于银行卡剩余的钱,而你此时又是跨行时,那么正确理解应该是先透支不够的钱然后再来取款最后来收由于跨行导致多透支的那部分钱,这个我是非常的不理解,最终的代码就应该是这样的:

if (account.getBank().getBankNO().equals(aTM.getBank().getBankNO())) {
            if (card.getCardType().equals("信用卡")) {
                if (balance - amount >= 0) {
                    account.setBalance(balance - amount);
                } else {
                    if (balance >= 0) {
                        account.setBalance((balance - amount) * 1.05);
                    } else {
                        account.setBalance(balance - amount * 1.05);
                    }
                }
            } else {
                account.setBalance(balance - amount);
            }

        } else {
            if (card.getCardType().equals("信用卡")) {
                if (balance - amount * (1 + aTM.getBank().getCommission()) >= 0) {
                    account.setBalance(balance - amount * (1 + aTM.getBank().getCommission()));
                } else {
                    if (balance >= 0) {
                        account.setBalance((balance - amount) * 1.05 - amount * aTM.getBank().getCommission());
                    } else {
                        account.setBalance(balance - amount * 1.05 - amount * aTM.getBank().getCommission());
                    }
                }
            } else {
                account.setBalance(balance - amount * (1 + aTM.getBank().getCommission()));//取款更新余额操作
            }
        }

这样子相当于分为了四种情况来讨论,然后再取款时又分了三种(第一种是不用透支,第二种是一部分透支,第三种是全部都要透支)。最后所有修改了的地方其实也就是这里(输出答案格式还改了下)。

从这里也可以看出其实并没有什么为难,没有通过说明我们在考虑是考虑的并不周全。

• 以上也就是这几题的入坑心得吧,虽然大部分其实我感觉还是没有很好的理解题目的意思,但是正是这样,我在一次一次的采坑总结之中总能发现自己的不足之处,也许这就是学习吧,毕竟失败乃成功之母,虽然这也不算是失败。

四、Improve 与 feel

1. 在这几次的题目来说,似乎现在我们需要考虑更多的是如何将代码设计的更加完美,不再是仅仅将作业做完了。通过这几次作业,明显感受到了面向对象思考的重要性了,如果设计的好,那么我们以后的工作量明显就会大大的降低,代码的复用性明显就会提高许多。

2. 在题目集7中,这里最为重要的是正确的使用多态和Comparable、Comparator 接口的应用,不然就会像我一样在找最大值时变得那么的冗余,繁琐了。

3. 在题目集8,9中主要就是要有着良好的面向对象思考的过程,在设计时不能随意设计,不贴近生活,甚至直接不设计类图,放在一个main类里面一写到底,完全没有体现出来面向对象的特点。在这里我发现面向对象的思考是十分的重要,如果以后在工作中,我们只是无脑的操作,那相必离职也就不远了。

面向对象的思考:从类的开发者角度来看,设计类时为了让很多不同的用户所使用。为了在更大的应用范围内使用类,类应通过构造方法、属性和方法提供各种方式的定制,就像是在这题ATM机中,没有设计,那么各个类的职责是什么,我们作为一个阅读者就无法知晓了,那么这样的话,完全就丧失了Java存在的意义了。从设计上来讲,我们还是得遵从这些,深刻理解这些毕竟大家说好才是真的好

 

 五、总结—感想

在这几次的学习中,我算是发现了其实入门一门语言是非常的快速的,但是要想深入理解一门语言应有的模样,还是非常具有难度的。就这几次的题目来说,我发现了对一门语言的设计的思考比你去敲代码更加有意思,因为我们要是设计好了所有的一切,那么敲代码只不过就是时间的问题了,最重要的还是要去深刻理解面向对象的真正含义,充分发挥Java所带来了便捷,各种功能等等。总的来说,学习的路还很长,我们需要不断的学习,不断的克服各种困难,这样才能看到最后时间给你证明的一切。


 

 总是相信:你今天的努力,是幸运的伏笔,当下的付出,是明日的花开。即使现在还看不到成果,请不要着急,最好的总会在最不经意的时候出现。让我们怀揣希望去努力,静待美好的出现。

 

 2021-06-09 09:45:25

 



这篇关于OO第三次Blog的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程