题目集8~9的总结性Blog

题目集总结

前言

时隔几周,又到了总结的时候了。这次主要针对第八次和第九次题目集进行总结,主要分析最后一个题。两次题目集总的来说难度比上一次低,主要锻炼类设计和继承多态的面向对象的思想。涉及的算法比较基础。同时需要灵活熟练的运用各种面向对象原则来完善和规范代码,保证代码的可维护性和可扩展性。

题目集8第一题

题目

点线面问题重构
在“点与线(类设计)”题目基础上,对题目的类设计进行重构,以实现继承与多态的技术性需求。
对题目中的点Point类和线Line类进行进一步抽象,定义一个两个类的共同父类Element(抽象类),将display()方法在该方法中进行声明(抽象方法),将Point类和Line类作为该类的子类。
再定义一个Element类的子类面Plane,该类只有一个私有属性颜色color,除了构造方法和属性的getter、setter方法外,display()方法用于输出面的颜色,输出格式如下:The Plane's color is:颜色
在主方法内,定义两个Point(线段的起点和终点)对象、一个Line对象和一个Plane对象,依次从键盘输入两个Point对象的起点、终点坐标和颜色值(Line对象和Plane对象颜色相同),然后定义一个Element类的引用,分别使用该引用调用以上四个对象的display()方法,从而实现多态特性。示例代码如下:

  element = p1;//起点Point
  element.display();
  
  element = p2;//终点Point
  element.display();
  
  element = line;//线段
  element.display();
  
  element = plane;//面
  element.display();

分析

这一题比较基础,主要是对之前写的点线面代码进行重构,加入继承和多态,优化代码结构,促进复用。增强扩展性,支持动态行为。如上面的示例代码所示,只需加入一个抽象类element即可,这个类作为Line,Plane,Point的父类,便可实现继承,同时,实现继承是为了实现多态,只要理解了多态是为了“同一接口,多种行为”,这道题便不攻自破了。it's a piece of cake.
献上类图:
image
附上源码:
``

点击查看代码
import java.util.Scanner;
public class Main {
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        double x1=sc.nextDouble();
        double y1=sc.nextDouble();
        double x2=sc.nextDouble();
        double y2=sc.nextDouble();
        String color=sc.next();
        if(x1<=0||x1>200||x2<=0||x2>200||y1>200||y1<=0||y2>200||y2<=0){
            System.out.println("Wrong Format");
            return ;
        }
        else{
            Element p1=new point(x1,y1);
            Element p2=new point (x2,y2);
            Element l=new line(p1,p2,color);
            Element plane=new Plane(color);
            p1.display();
            p2.display();
            l.display();
            plane.display();
        }
    }
}
class line extends Element{
    private point p1;
    private point p2;
    private String color;

    public line() {
    }
public line(Element p1, Element p2,String color){
        super();
        this.color=color;
        this.p1=(point)p1;
        this.p2=(point)p2;
}
    public line(point p1, point p2, String color) {
        this.p1 = p1;
        this.p2 = p2;
        this.color = color;
    }

    public point getP1() {
        return p1;
    }

    public void setP1(point p1) {
        this.p1 = p1;
    }

    public point getP2() {
        return p2;
    }

    public void setP2(point p2) {
        this.p2 = p2;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
    public double getDistance(){
       double dis=Math.sqrt((p1.getX()-p2.getX())*(p1.getX()-p2.getX())+(p1.getY()-p2.getY())*(p1.getY()-p2.getY()));
return Double.parseDouble(String.format("%.2f",dis));
    }
    @Override
    public void display() {
        System.out.printf("The line's color is:"+color+"\n");
       System.out.printf("The line's begin point's Coordinate is:\n" + "(%.2f,%.2f)\n", p1.getX(),p1.getY());
      System.out.printf("The line's end point's Coordinate is:\n" + "(%.2f,%.2f)\n", p2.getX(), p2.getY());
        System.out.printf("The line's length is:%.2f\n",getDistance());
    }
}
class Plane  extends Element {
private String color;
public Plane(){

}
public Plane(String color){
    this.color =color;

}
public String getColor(){
    return this.color;
}
public void setColor(String color){
    this.color = color;
}
@Override
    public void display(){
    System.out.printf("The Plane's color is:"+color);
}
}
abstract class Element {
    public void display(){}

}
class point extends Element{
    private double x;
    private double y;
    public point (){

    }
    public point (double x,double y){
        this.x=x;
        this.y=y;
    }
    public double getX(){
        return x;
    }
    public void setX(double x){
        this.x=x;
    }
    public double getY(){
        return y;
    }
    public void setY(double y){
        this.y=y;
    }
    @Override
    public void display(){
        System.out.printf("(%.2f,%.2f)\n",x,y);
    }
}

题目集8第二题

题目

NCHU_雨刷程序功能扩展设计
在给定的汽车手动风挡玻璃雨刷程序的基础上,对程序进行重构(Refactoring),使得程序可以对功能进行扩展。

分析

又是一道对原先做过题的refactoring,通过使用面向对象分析及设计,进一步了解面向过程程序设计以及面向对象程序设计的区别及联系,总结两种程序设计方法其各自适用的场景。这道题的难度不大,但要求是能够实现表一及表二所描述的不同雨刷系统类型,同时使得程序在符合单一职责原则、迪米特法则、合成复用原则的基础上具有良好的扩展性(开-闭原则)、里氏代换原则、接口隔离原则及依赖倒转原则。鉴于上述要求,要想好以下几个问题
(1)如何体现单一职责原则及类的封装性;
(2)如何运用多态实现系统的可扩展性;
(3)系统扩展时接口与抽象类在设计中的地位及作用。
给出类图:
image

附上源码:

点击查看代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args){
        int choice = 0;
        Scanner input = new Scanner(System.in);
        int a=input.nextInt();
        if(a==1){
            choice = input.nextInt();

            LeverKind lever = new Lever(1);
            DialKind dial = new Dial(1);
            Brush brush = new Brush(0);

            Agent agent = new Agent((Lever)lever,(Dial)dial,brush);
int k=1;
            while (choice != 0) {
                switch (choice) {
                    case 1://Lever up
                        agent.getLever().leverUp();
                        System.out.print("Lever up/");
                        agent.read1();
                        agent.read2();
                        System.out.print("/");
                        break;
                    case 2://Lever down
                        agent.getLever().leverDown();
                        System.out.print("Lever down/");
                        agent.read1();
                        agent.read2();
                        System.out.print("/");
                        break;
                    case 3://Dial up
                        agent.getDial().dialUp();
                        System.out.print("Dial up/");
                        agent.read1();
                        agent.read2();
                        System.out.print("/");
                        break;
                    case 4://Dial down
                        agent.getDial().dialDown();
                        System.out.print("Dial down/");
                        agent.read1();
                        agent.read2();
                        System.out.print("/");
                        break;
                    case 0://Terminate
                        System.exit(0);
                    default:
                        k=0;
                }

if(k==1){
                agent.dealSpeed();//Get brush’s speed

                System.out.println(agent.getBrush().getSpeed());}
k=1;
                choice = input.nextInt();}
               
            
        }
        else if(a==2){
            choice = input.nextInt();

            Lever1 lever1 = new Lever1(1);
            Dial1 dial1 = new Dial1(1);
            Brush brush = new Brush(0);

            Agent1 agent1 = new Agent1(lever1,dial1,brush);

            while (choice != 0) {
                switch (choice) {
                    case 1://Lever up
                        agent1.getLever1().leverUp();
                        System.out.print("Lever up/");
                        agent1.read1();
                        agent1.read2();
                        System.out.print("/");
                        break;
                    case 2://Lever down
                        agent1.getLever1().leverDown();
                        System.out.print("Lever down/");
                        agent1.read1();
                        agent1.read2();
                        System.out.print("/");
                        break;
                    case 3://Dial up
                        agent1.getDial1().dialUp();
                        System.out.print("Dial up/");
                        agent1.read1();
                        agent1.read2();
                        System.out.print("/");
                        break;
                    case 4://Dial down
                        agent1.getDial1().dialDown();
                        System.out.print("Dial down/");
                        agent1.read1();
                        agent1.read2();
                        System.out.print("/");
                        break;
                    case 0://Terminate
                        System.exit(0);
                }


                agent1.dealSpeed();//Get brush’s speed

                System.out.println(agent1.getBrush().getSpeed());

                choice = input.nextInt();
            }

        }
        else{
            System.out.println("Wrong Format");
        }
    }}
interface Agentkind {
    public void dealSpeed();
    public void read2();
    public void read1();
}
class Agent implements Agentkind {
    //聚合型类设计
    private Lever lever;
    private Dial dial;
    private Brush brush;

    public Agent(){

    }

    public Agent(Lever lever,Dial dial,Brush brush){
        this.lever = lever;
        this.dial = dial;
        this.brush = brush;
    }

    public Lever getLever() {
        return lever;
    }

    public void setLever(Lever lever) {
        this.lever = lever;
    }

    public Dial getDial() {
        return dial;
    }

    public void setDial(Dial dial) {
        this.dial = dial;
    }

    public Brush getBrush() {
        return brush;
    }

    public void setBrush(Brush brush) {
        this.brush = brush;
    }

    //主要业务逻辑:根据控制杆档位、刻度盘刻度计算雨刷摆动速度
    public void dealSpeed(){
        int speed = 0;

        switch(this.lever.getPos()){
            case 1://停止
                speed = 0;break;
            case 2://间歇
                switch(this.dial.getPos()){
                    case 1://刻度1
                        speed = 4;break;
                    case 2://刻度2
                        speed = 6;break;
                    case 3://刻度3
                        speed = 12;break;

                }
                break;
            case 3://低速
                speed = 30;break;
            case 4://高速
                speed = 60;break;

        }

        this.brush.setSpeed(speed);
    }
    public void read2(){
        if(dial.getPos()==1)
            System.out.print("1");
        if(dial.getPos()==2)
            System.out.print("2");
        if(dial.getPos()==3)
            System.out.print("3");

    }
    public void read1(){
        if(lever.getPos()==1)
            System.out.print("停止/");
        if(lever.getPos()==2)
            System.out.print("间歇/");
        if(lever.getPos()==3)
            System.out.print("低速/");
        if(lever.getPos()==4)
            System.out.print("高速/");


    }
}
class Agent1 implements Agentkind {
    //聚合型类设计
    private Lever1 lever1;
    private Dial1 dial1;
    private Brush brush;

    public Agent1(){

    }

    public Agent1(Lever1 lever1,Dial1 dial1,Brush brush){
        this.lever1 = lever1;
        this.dial1= dial1;
        this.brush = brush;
    }

    public Lever1 getLever1() {
        return lever1;
    }

    public void setLever1(Lever1 lever1) {
        this.lever1 = lever1;
    }

    public Dial1 getDial1() {
        return dial1;
    }

    public void setDial1(Dial1 dial1) {
        this.dial1 = dial1;
    }

    public Brush getBrush() {
        return brush;
    }

    public void setBrush(Brush brush) {
        this.brush = brush;
    }

    //主要业务逻辑:根据控制杆档位、刻度盘刻度计算雨刷摆动速度
    public void dealSpeed(){
        int speed = 0;

        switch(this.lever1.getPos()){
            case 1://停止
                speed = 0;break;
            case 2://间歇
                switch(this.dial1.getPos()){
                    case 1://刻度1
                        speed = 4;break;
                    case 2://刻度2
                        speed = 6;break;
                    case 3://刻度3
                        speed = 12;break;
                    case 4:
                        speed=15;break;
                    case 5:
                        speed=20;break;
                }
                break;
            case 3://低速
                speed = 30;break;
            case 4://高速
                speed = 60;break;
            case 5:
                speed =90;break;
        }

        this.brush.setSpeed(speed);
    }
    public void read2(){
        if(dial1.getPos()==1)
            System.out.print("1");
        if(dial1.getPos()==2)
            System.out.print("2");
        if(dial1.getPos()==3)
            System.out.print("3");
        if(dial1.getPos()==4)
            System.out.print("4");
        if(dial1.getPos()==5)
            System.out.print("5");

    }
    public void read1(){
        if(lever1.getPos()==1)
            System.out.print("停止/");
        if(lever1.getPos()==2)
            System.out.print("间歇/");
        if(lever1.getPos()==3)
            System.out.print("低速/");
        if(lever1.getPos()==4)
            System.out.print("高速/");
        if(lever1.getPos()==5)
            System.out.print("超高速/");


    }
}
interface LeverKind {
    public void leverUp();
    public void leverDown();
}
class Lever implements LeverKind {
    private int pos;//档位

    public Lever(){

    }

    public Lever(int pos){
        this.pos = pos;
    }

    public int getPos() {
        return pos;
    }

    //升档
    @Override
    public void leverUp() {
        if(this.pos < 4){
            this.pos ++;
        }
    }

    //降档
    @Override
    public void leverDown(){
        if(this.pos > 1){
            this.pos --;
        }
    }

}
class Lever1 implements LeverKind {
    private int pos;//档位

    public Lever1(){

    }
    public abstract class DialKind {

        private int pos;//刻度

        public DialKind(){

        }

        public DialKind(int pos){
            this.pos = pos;
        }

        public int getPos() {
            return pos;
        }

        //升刻度
        public abstract void dialUp();

        //降刻度
        public abstract void dialDown();

    }
    class Dial extends DialKind{
        private int pos;//刻度

        public Dial(){

        }

        public Dial(int pos){
            this.pos = pos;
        }

        public int getPos() {
            return pos;
        }

        //升刻度
        @Override
        public void dialUp() {
            if(this.pos < 3){
                this.pos ++;
            }
        }

        //降刻度
        @Override
        public void dialDown(){
            if(this.pos > 1){
                this.pos --;
            }
        }

    }


    public Lever1(int pos){
        this.pos = pos;
    }

    public int getPos() {
        return pos;
    }

    //升档
    @Override
    public void leverUp() {
        if(this.pos < 5){
            this.pos ++;
        }
    }

    //降档
    @Override
    public void leverDown(){
        if(this.pos > 1){
            this.pos --;
        }
    }

}
class Dial1 extends DialKind
{private int pos;//刻度

    public Dial1(){

    }

    public Dial1(int pos){
        this.pos = pos;
    }

    public int getPos() {
        return pos;
    }

    //升刻度
    @Override
    public void dialUp() {
        if(this.pos < 5){
            this.pos ++;
        }
    }

    //降刻度
    @Override
    public void dialDown(){
        if(this.pos > 1){
            this.pos --;
        }
    }}
class Dial extends DialKind{
    private int pos;//刻度

    public Dial(){

    }

    public Dial(int pos){
        this.pos = pos;
    }

    public int getPos() {
        return pos;
    }

    //升刻度
    @Override
    public void dialUp() {
        if(this.pos < 3){
            this.pos ++;
        }
    }

    //降刻度
    @Override
    public void dialDown(){
        if(this.pos > 1){
            this.pos --;
        }
    }

}
abstract class DialKind {

    private int pos;//刻度

    public DialKind(){

    }

    public DialKind(int pos){
        this.pos = pos;
    }

    public int getPos() {
        return pos;
    }

    //升刻度
    public abstract void dialUp();

    //降刻度
    public abstract void dialDown();

}
 class Brush {
    private int speed;

    public Brush(){

    }

    public Brush(int speed){
        this.speed = speed;
    }

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }
}



题目集8第三题(重点)

题目概述

https://images.ptausercontent.com/499d204b-fcef-4610-a9ca-c8fbf5e346d9.pdf

设计与分析

首先,题目并没有给出类图,但是根据面向对象的设计原则,需要我们自己来设计类和类之间的关系,要体现单一职责原则,里氏代换原则,依赖倒置原则和开闭原则等思想。同时,这个题目又要有很好的可扩展性和可维护性才可应对下一次继承和多态的重构题。
接着,根据题目意思设计实体类,使其满足单一职责原则,尽量与其他类尽可能少的耦合,像订单类里处理商品的方法可以单独成为一个处理订单的类。
设计好全部实体类后,为了操控实体类,我们可以设计一些control类来关联这些类。同时,这里有一个计算费率的简单算法,根据不同计费重量来决定费率从而来计算运费。这个计算本身不难,不过有个坑就是所有的重量其实都说按计费重量算的,这个细节没把握好,很可能能过测试样例,却过不了测试点,这样一来也很难发现错误,所以这警示我们读题要认真,同时要以题目意思为引导,而不是转牛角尖。
那好,现在开始具体分析。
先给出类图:
image
image
类图面向对象设计原则中的单一职责原则、里氏代换原则、开
闭原则以及合成复用原则。

概念解析

1.计费重量:

空运以实际重量(GrossWeight)和体积重量(VolumeWeight)中的较
高者作为计费重量。
计算公式:
体积重量(kg)= 货物体积(长×宽×高,单位:厘米)÷6000
示例:
若货物实际重量为80kg,体积为120cm×80cm×60cm,则:
体积重量 =(120×80×60)÷6000=96kg
计费重量取96kg(因96kg>80kg)

2.运费计算:
基础运费 = 计费重量 × 费率

SourceMoniter报表分析

image
这份报告是针对 Main.java 文件的代码质量分析结果,主要包含 代码复杂度、结构、可维护性 等指标。可以看到有以下几个问题:

1.Percent Lines with Comments (注释率)过低。注释率只有2.3%,提升至 10%~20% 以增强可读性
2.Maximum Complexity (最大复杂度) 5 (最大复杂度方法:DealOrder.getRate()) 接近高风险阈值(≥5),需要检查逻辑是否可简化.

同时,
Methods per Class (方法数/类) 8.00 合理范围(通常 5~15)。
Average Complexity (平均复杂度) 1.93 良好(1~2 为简单,3~5 中等,>5 需重构)。这两方面都在合理范围内。

代码分析

由于各个类的实现其实都不难,这里着重讲解主函数和控制类。

1.容器的使用(ArrayList)
点击查看代码
// 货物信息
    ArrayList<String> productName = new ArrayList<>();
    ArrayList<Double> productWidth = new ArrayList<>();
    ArrayList<Double> productLength = new ArrayList<>();
    ArrayList<Double> productHeight = new ArrayList<>();
    ArrayList<Double> productWeight = new ArrayList<>();
    ArrayList<Integer> productNumber = new ArrayList<>();

点击查看代码
private  ArrayList<Double> rate = new ArrayList<>();
   private ArrayList<Double>money  = new ArrayList<>();

这里将商品的各个信息和各个物品的金额数以及费率用arrayList容器来接收。

2. \t的作用

这里是一个小的知识盲点。或者说没真正明白这个的作用。借此机会百度总结一下。
\t 是一个 转义字符,代表 水平制表符(Horizontal Tab),其作用类似于键盘上的 Tab 键。核心作用就是分隔数据:在表格或结构化文本中分隔列(如 CSV 文件用 \t 替代逗号)。

3.日期类的使用

这里需要输入日期,而java有关于日期的类和方法供我们使用来提高我们的编码效率。

点击查看代码
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
String flightDate1 = sc.nextLine();
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    LocalDate flightDate = LocalDate.parse(flightDate1, formatter);

这里需要提醒一下,虽然这个日期类只是记忆性的内容,也不需要完全记住,但是我们仍然需要了解和会运用,所以即使简单也再回顾一下。

题目集9第一题

题目概述:

NCHU_魔方问题
问题描述:本问题中的魔方有两种,一种是正方体魔方,一种是正三棱锥魔方,其中,正方体或正三棱锥魔方是由单元正方体或正三棱锥组成,单元正方体或正三棱锥的个数由阶数(即层数)决定,即魔方边长=阶数*单元边长。魔方如下图所示:略
输入样例:
在这里给出一组输入。例如:

red 3 4.5
black 4 2.1
输出样例:
在这里给出相应的输出。例如:

red
1093.50
2460.38
black
122.21
69.85

设计与分析

老样子,第一题不是很难,需要注意的是这里需要算面积和体积,要回顾高中学的立体几何算体积的公式,如果不记得也可直接百度。这个题目主要锻炼我们的继承和多态的熟练和灵活运用程度。
奉上主函数:

点击查看代码
public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner input = new Scanner(System.in);
        
        String color = input.next();
        int layer = input.nextInt();
        double side = input.nextDouble();        
        
        RubikCube cube1 = new SquareCube(color, layer,new Cube(side)); 
                
        color = input.next();
        layer = input.nextInt();
        side = input.nextDouble();
        
        RubikCube cube2 = new RegularPyramidCube(color, layer,new RegularPyramid(side));
        display(cube1);
        display(cube2);
    }
}

奉上类图:
image

题目集9第二次作业

题目概述

NCHU_点线面问题再重构(容器类)
在“点与线(继承与多态)”题目基础上,对题目的类设计进行重构,增加容器类保存点、线、面对象,并对该容器进行相应增、删、遍历操作。
在原有类设计的基础上,增加一个GeometryObject容器类,其属性为ArrayList类型的对象(若不了解泛型,可以不使用
增加该类的add()方法及remove(int index)方法,其功能分别为向容器中增加对象及删除第index - 1(ArrayList中index>=0)个对象
在主方法中,用户循环输入要进行的操作(choice∈[0,4]),其含义如下:
1:向容器中增加Point对象
2:向容器中增加Line对象
3:向容器中增加Plane对象
4:删除容器中第index - 1个数据,若index数据非法,则无视此操作
0:输入结束

设计与分析

这个题目明确了在题目集8的点面线的基础上加入容器。只要熟练掌握容器的概念问题就解决了。有了题集8的代码,在此基础上做refactoring,也不是什么难事。
奉上类图:
image
奉上源码:

点击查看代码
import java.util.Scanner;
import  java.util.ArrayList;
public class Main {
    public static void main(String []args){
        Scanner input=new Scanner(System.in);


        GeometryObject g = new GeometryObject();
               int choice = input.nextInt();
                while(choice != 0) {
                    switch(choice) {
                        case 1://insert Point object into list
                  double x = input.nextDouble();
                  double y = input.nextDouble();
                  Element element  = new point(x,y);
                                g.add(element);

                            break;
                        case 2://insert Line object into list
                            double x1 = input.nextDouble();
                            double y1= input.nextDouble();
                            double x2 = input.nextDouble();
                            double y2 = input.nextDouble();
                            String color  = input.next();
                            Element element1  = new point(x1,y1);
                            Element element2  = new point(x2,y2);
                            Element element3 = new line(element1,element2,color);
                            g.add(element3);
                            break;
                        case 3://insert Plane object into list
                            String color1 = input.next();
                            Element element4 = new Plane(color1);
                            g.add(element4 );
                            break;
                        case 4://delete index - 1 object from list

                            int index = input.nextInt();
                            if(index>g.getList().size()||index<1){
                                break;
                            }
                            g.remove(index-1);
                            break;
                        case 0:
                            break;
                    }
                    choice = input.nextInt();
                }
                for(int i =0;i<g.getList().size();i++){
                    g.getList().get(i).display();
                }
            }
        }
 abstract class Element {
    public void display(){}

}

 class point extends Element{
    private double x;
    private double y;
    public point (){

    }
    public point (double x,double y){
        this.x=x;
        this.y=y;
    }
    public double getX(){
        return x;
    }
    public void setX(double x){
        this.x=x;
    }
    public double getY(){
        return y;
    }
    public void setY(double y){
        this.y=y;
    }
    @Override
    public void display(){
        System.out.printf("(%.2f,%.2f)\n",x,y);
    }
}


 class Plane  extends Element {
private String color;
public Plane(){

}
public Plane(String color){
    this.color =color;

}
public String getColor(){
    return this.color;
}
public void setColor(String color){
    this.color = color;
}
@Override
    public void display(){
    System.out.printf("The Plane's color is:%s\n",color);
}
}

 class line extends Element{
    private point p1;
    private point p2;
   private String color;

    public line() {
    }
public line(Element p1, Element p2,String color){
        super();
       this.color=color;
        this.p1=(point)p1;
        this.p2=(point)p2;
}
    public line(point p1, point p2,String color) {
        this.p1 = p1;
        this.p2 = p2;
        this.color = color;
    }

    public point getP1() {
        return p1;
    }

    public void setP1(point p1) {
        this.p1 = p1;
    }

    public point getP2() {
        return p2;
    }

    public void setP2(point p2) {
        this.p2 = p2;
    }


    public void setColor(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    public double getDistance(){
       double dis=Math.sqrt((p1.getX()-p2.getX())*(p1.getX()-p2.getX())+(p1.getY()-p2.getY())*(p1.getY()-p2.getY()));
return Double.parseDouble(String.format("%.2f",dis));
    }
    @Override
    public void display() {
        System.out.printf("The line's color is:"+color+"\n");
       System.out.printf("The line's begin point's Coordinate is:\n" + "(%.2f,%.2f)\n", p1.getX(),p1.getY());
      System.out.printf("The line's end point's Coordinate is:\n" + "(%.2f,%.2f)\n", p2.getX(), p2.getY());
        System.out.printf("The line's length is:%.2f\n",getDistance());
    }
}

 class GeometryObject {
    private ArrayList<Element> list   = new ArrayList<>();

    public GeometryObject() {
    }
    public void add(Element element){
           list.add(element);
    }
    public void remove(int index){
          list.remove(index);
    }

    public ArrayList<Element> getList() {
        return list;
    }
}

题目集9第三题

题目概述

请见文档
https://images.ptausercontent.com/b9cec79b-8012-4901-843e-3d48f27d28a6.pdf
输入输出格式与题集八一模一样,这里不再赘述。

设计与分析

首先,我们先搞清楚我们这次题目是在第八次的基础上进行重构的,所以不需要重新再写一遍,找到第八次的代码,明确需要扩展和完善的点即可。
仔细阅读文档,总结可知:本题需求可扩展的类:用户、支付方式、货物
画一个草图:
image

给出类图:
image

关键关系与设计模式

继承关系

Person ← Customer ← (Individual/Corporate):人员角色的层次化设计。

Product ← (QuickProduct/RiskProduct):通过重写getRate()实现策略模式,支持不同产品的费率计算。

Pay ← (WechatPay/AliPay/Cash):支付方式的多态扩展。

组合/聚合关系

DealOrder 聚合了 Order、ArrayList、Person、Fights:表示订单依赖这些对象完成业务逻辑。

抽象与接口

Person和Pay为抽象类,强制子类实现通用行为(如pay())。

SM报表分析

image
有以下问题:

Maximum Complexity (最大复杂度) 14 (Main.main()) 超安全阈值(≥10)

Percent Lines with Comments (注释率) 3.2% 远低于推荐值(10%~20%),影响可维护性。

Average Statements per Method (方法平均语句数) 9.00 推荐≤6,表明方法功能过于复杂。

总结

经过了为期两周的训练,经过为期两周的题目集训练,在面向对象编程的理解与实践上有了显著提升。从基础的类继承与多态重构,到复杂系统的设计原则应用,逐步体会到面向对象思想如何通过抽象、封装、继承和多态来降低代码复杂度、提升可维护性。例如,在点线面问题中,通过抽象类Element统一接口,使不同图形对象(点、线、面)能够以一致的方式被处理,充分体现了多态的优势;而在雨刷系统和空运计费系统中,遵循单一职责和开闭原则,通过接口隔离不同功能模块,有效避免了代码的紧耦合。同时我学到了和认识到了一下几点。
1.强化设计原则意识:在编码前先梳理类之间的关系,优先考虑使用抽象类或接口定义公共行为,确保代码符合单一职责、里氏代换等原则,避免后期重构成本过高。
2.注重代码可读性与注释:本次题目集中暴露出注释率低的问题(如部分代码注释率仅 2.3%),建议在关键逻辑处添加注释,说明设计意图和算法思路,提升代码可维护性。
3.分模块测试与调试:面对复杂功能(如空运计费的多条件费率计算),可将大问题拆解为小模块,逐一测试(如单独验证体积重量计算逻辑),减少集成错误。
4.问题拆解与抽象能力:在空运计费系统中,将复杂需求拆解为 “货物信息录入→计费重量计算→费率匹配→运费计算” 多个模块,每个模块对应独立的类或方法(如DealOrder处理订单逻辑,Product封装货物属性),逐步构建完整逻辑链。
5.抽象能力:体现在提炼公共行为,如将 “显示” 行为抽象为Element的display()方法,将 “计算” 行为抽象为Solid的getArea()和getVolume()方法,避免重复代码。
以上就是本次博客全部内容,感谢观看。

posted @ 2025-05-18 15:42  太妙了  阅读(66)  评论(0)    收藏  举报