面向对象—有理数类的设计
目录
1.代码呈现
1.1编写toString、equals方法
1.2测试代码
1.3有理数类的代码
2.论述题
3.有理类设计
1.代码呈现
1.1编写toString、equals方法
(1)toString方法
@Overridepublic String toString(){if(this.v2==0){return "Undefined";}return this.v1 +"/"+ this.v2;}
(2)equals方法
@Overridepublic boolean equals(Object obj) {// 首先检查引用是否相同if (this == obj) {return true;}// 检查是否为同一个类的对象if (!(obj instanceof Rational)) {return false;}// 强制转换为 Rational 类型Rational other = (Rational) obj;// 检查分母是否为零,如果其中一个对象的分母为零,则它们不能相等if( v2 == 0 || other.v2 == 0) {return false;}// 计算两个有理数的交叉乘积并比较return (v1 * other.v2) == (other.v1 * v2);}
1.2测试代码
(1)在与有理数类不同包的其他类中调用有理数类
(2)测试代码与测试结果
package test01;import Rational.Rational;public class Rationaltest {public static void main(String[] args) {// 创建两个有理数对象Rational r1 = new Rational(1, 2); // 1/2Rational r2 = new Rational(3, 4); // 3/4// 创建第三个对象用于存放结果Rational result = new Rational(0, 1);//分母不能为0// 测试加法System.out.println("Adding 1/2 and 3/4:");r1.Add(r1, r2, result);System.out.println("Result= " + result.getV1() + "/" + result.getV2());// 测试乘法System.out.println("Multiplying 1/2 and 3/4:");r1.Multiply(r1, r2, result);System.out.println("Result= " + result.getV1() + "/" + result.getV2());//测试getRationalSystem.out.println("getRational:");int e=0;System.out.println("e="+r1.getRational(r1,2,e));//toStringSystem.out.println("r1 的输出结果为: ");System.out.println("r1 = "+r1.toString());//equalsSystem.out.println("r1和r2的比较结果为:");System.out.println(r1.equals(r2));} }
1.3有理数类的代码
package Rational;public class Rational{//属性private int v1;private int v2;//构造函数public Rational(int v1,int v2){this.v1=v1;this.v2=v2;}//setter与getterpublic int getV1() {return v1;}public void setV1(int v1) {this.v1 = v1;}public int getV2() {return v2;}public void setV2(int v2) {this.v2 = v2;}//方法//add方法public void Add(Rational T1,Rational T2,Rational T3){int t;T3.v2 = T1.v2 * T2.v2;T3.v1 = T1.v1 * T2.v2 + T2.v1 * T1.v2;t = Gcd(T3.v2,T3.v1);T3.v2 /= t;T3.v1 /= t;}//Multiply方法public void Multiply(Rational T1,Rational T2,Rational T3){int t;T3.v2 = T1.v2 * T2.v2;T3.v1 = T1.v1 * T2.v1;t = Gcd(T3.v2, T3.v1);T3.v2 /= t;T3.v1 /= t;}private static int Gcd(int m,int n){int t;while(m % n != 0){t = n;n = m%n;m = t;}return n;}public int getRational(Rational T,int i,int e){if(i==1){e=T.v1;}else{e=T.v2;}return e;}@Overridepublic String toString(){if(this.v2==0){return "Undefined";}return this.v1 +"/"+ this.v2;}@Overridepublic boolean equals(Object obj) {// 首先检查引用是否相同if (this == obj) {return true;}// 检查是否为同一个类的对象if (!(obj instanceof Rational)) {return false;}// 强制转换为 Rational 类型Rational other = (Rational) obj;// 检查分母是否为零,如果其中一个对象的分母为零,则它们不能相等if( v2 == 0 || other.v2 == 0) {return false;}// 计算两个有理数的交叉乘积并比较return (v1 * other.v2) == (other.v1 * v2);}
}
2.论述题
1.尝试回答与c语言的有理数代码相比较,为什么你设计的类更加面向对象?
(1)
- 在Java中,我们利用类来封装数据和行为。我们将有理数的分子分母封装在一个类里,并通过方法(get方法)的调用来访问数据,且类里的数据都被保护起来,不允许外部直接修改。
- 而在C语言中,通常利用结构体来存储数据,数据是公开的可以任意修改。
(2)
- 在 Java 中,方法属于类的一部分。每个 Rational对象都有自己的方法,如加法、减法等。这些方法可以直接在对象上调用,使得代码更加直观和易于理解。
- 在 C 语言中,方法通常是独立于数据结构的全局函数。虽然可以通过传递指向结构体的指针来操作数据,但这不如 Java 中的对象方法那样自然。
(3)
- Java 支持继承,允许从现有类派生新类(利用extends关键字)。子类可以复用父类的行为并添加新的特性。
- C 语言没有内置的继承机制。虽然可以通过包含结构体或其他技巧来模拟继承,但这种做法并不像 Java 中那么直接和强大。
2. 尝试从代码复用的角度来描述你设计的有理数类。从几个方面讨论。
2.1别人如何复用你的代码?
(1)通过注释了解类的属性和方法,必要时在JDK文档中查找类的功能
(2)通过代码测试检测代码是否可以正常运行
2.2别人的代码是否依赖你的有理数类的内部属性?当你升级了你的有理数类,将其的属性名改变时。是否会影响他人以前编写的调用你有理数类的代码(假设他将使用了你升级后有理数类)?
(1)封装是面向对象编程的一个核心原则,它确保了对象的内部状态对外部是不可见的,并且只能通过定义好的方法来访问和修改。
(2)私有化(private)Rational类的属性且提供公共的方法(getV1()和getV2())访问。
(3)
ational
类遵循了良好的封装原则,并且外部代码只通过公共接口(如 getter 和 setter 方法、运算方法等)来访问和操作Rational
对象,那么更改类的内部属性名不会影响外部代码。这是因为外部代码并不直接依赖于这些内部属性。
2.3有理数类的public方法是否设置合适?为什么有的方法设置为private?
(1)Rational类中的public方法有:构造函数,setter与getter方法,运算方法(add,multiply),toString(),equals()。
公共方法是类对外提供的接口,用户可以通过这些方法与对象进行交互。
(2)Rational类中的private方法有:Gcd()。
私有方法是类的内部实现细节,外部代码无法直接调用这些方法。将类中的辅助方法(Gcd())设为私有方法。避免外部代码直接调用他们,有利于保护内部的状态。
2.4你的类里面有static属性或方法吗?如果有,为什么要设置为static的?
类中的工具方法(提供辅助的方法),如Rational类中的Gcd()。设置为static那么方法可以通过类名直接调用,而不需要创建类的实例。
//求最大公约数 private static int Gcd(int m,int n){int t;while(m % n != 0){t = n;n = m%n;m = t;}return n;}
3.有理类设计
在设计面向对象的有理数类时,我深刻体会到了面向对象编程的精髓,也发现了自己在设计过程中的一些不足。
有理数类的设计需要考虑数据的封装、方法的实现以及异常处理等多个方面。通过将分子和分母封装为私有成员变量,并提供公共的构造函数和方法,我成功实现了有理数的基本运算,如加法、减法、乘法和除法。同时,我也为有理数类添加了化简功能,确保结果总是以最简形式表示。
然而,在设计过程中,我也遇到了一些问题。例如,我没有充分考虑到分母为零的情况,导致程序在运行时可能会出现异常。此外,在实现有理数的比较方法时,我最初没有考虑到浮点数精度问题,导致比较结果可能不准确。通过不断调试和优化,我逐步解决了这些问题,并加深了对面向对象编程的理解。
这次设计让我认识到,面向对象编程不仅仅是代码的封装,更是一种思维方式。我们需要从对象的角度去思考问题,将问题分解为一个个类和对象,并通过合理的方法和属性来实现功能。同时,我也意识到在设计过程中要充分考虑各种边界情况和异常情况,以提高程序的健壮性和可靠性。