根据周长计算不同形状图形的面积,详细要求如下:
1. 计算多种图形的面积,并比较各种图形面积的最大值。
2. 使用抽象类及其子类的方式实现本案例。
3. 本案例以圆形和正方形为例。
注:正方形的面积公式为:0.0625*c*c。圆形的面积公式为:0.0796*c*c,其中,c表示图形的周长。
分析问题中的描述,可以得出如下解决方案:
1. 定义两个类Square和Circle,分别表示正方形和圆形。
2. 正方形和圆形都有周长,我们可以使用c属性来表示;要计算正方形和圆形的面积,我们定义area方法来实现。即,分别在Square类和Circle类中定义c属性和area方法,并根据各自图形的公式计算对应的面积。
3. 案例问题中要求计算各种图形的面积,并找出最大值。在此,我们需要找到一种类型,该类型为Square类和Circle类的父类,使用该类型的数组来存储所有图形。因此,定义Shape类,该类为Square和Circle类的父类,并将Square类和Circle类的共有属性放入Shape类中定义。
4. 又因为父类(Shape)的引用不能直接调用子类(Square或Circle)的方法(area方法),因此,将area方法抽取到父类Shape中。在父类Shape中,不知道具体是哪种图形,因此area方法不知如何实现,在此,将该方法定义抽象方法,那么Shape类也要定义为抽象类。这样,也形成了子类(Square或Circle)重写父类(Shape)的area方法。
5. 最后,我们就可以定义如下方法来实现求面积的最大值:
public static void maxArea(Shape[] shapes) { Shape s0 = shapes[0]; double max = s0.area(); int maxIndex = 0; for (int i = 1; i < shapes.length; i++) { double area = shapes[i].area(); if (area > max) { max = area; maxIndex = i; } } System.out.println("数组中索引为"+maxIndex+"的图形的面积最大,面积为:"+max); }
以上方法中,参数shapes为Shape[]数组类型,该参数中可以存储正方形、圆形、或是其它图形。
实现此案例需要按照如下步骤进行。
步骤一:定义类Square和Circle
定义两个类Square和Circle,分别表示正方形和圆形,Square类代码如下所示:
public class Square { }
Circle类代码如下所示:
public class Circle { }
步骤二:定义c属性和area方法
分别在Square类和Circle类中定义c属性和area方法,并根据各自图形的公式计算对应的面积,Square类代码如下所示:
public class Square { #cold_boldprivate double c; #cold_bold public Square(double c) { #cold_bold this.c = c; #cold_bold } #cold_bold /** #cold_bold * 计算正方形的面积 #cold_bold */ #cold_bold public double area() { #cold_bold return 0.0625*c*c; #cold_bold } }
Circle类代码如下所示:
public class Circle { #cold_boldprivate double c; #cold_bold public Circle(double c) { #cold_bold this.c = c; #cold_bold } #cold_bold /** #cold_bold * 计算圆形的面积 #cold_bold */ #cold_bold public double area() { #cold_bold return 0.0796*c*c; #cold_bold } }
步骤三:定义父类Shape并抽取属性和方法
定义父类Shape,将子类Square和Circle中共有属性c和方法area抽取到父类Shape中,并重构Square类和Circle类,Shape类代码如下所示:
public abstract class Shape { protected double c; public abstract double area(); }
Square类代码如下所示:
#cold_boldpublic class Square extends Shape { public Square(double c) { this.c = c; } /** * 计算正方形的面积 */ public double area() { return 0.0625*c*c; } }
Circle类代码如下所示:
#cold_boldpublic class Circle extends Shape { public Circle(double c) { this.c = c; } /** * 计算圆形的面积 */ public double area() { return 0.0796*c*c; } }
步骤四:计算各种图形面积的最大值
新建类TestShape,在该类中新建方法maxArea方法,该方法实现计算多种图形面积的最大值,代码如下所示:
public class TestShape{ public static void maxArea(Shape[] shapes) { double max = shapes[0].area(); int maxIndex = 0; for (int i = 1; i < shapes.length; i++) { double area = shapes[i].area(); if (area > max) { max = area; maxIndex = i; } } System.out.println("数组中索引为"+maxIndex+"的图形的面积最大,面积为:"+max); } }
步骤五:测试
在TestShape类中,测试maxArea方法能否计算出各种图形面积的最大值,代码如下所示:
public class TestShape { #cold_bold public static void main(String[] args) { #cold_bold Shape[] shapes = new Shape[2]; #cold_bold shapes[0] = new Circle(4);//数组中的第一个元素为圆形对象,周长为4 #cold_bold shapes[1] = new Square(4);//数组中的第二个元素为正方形对象,周长为4 #cold_bold maxArea(shapes); #cold_bold } public static void maxArea(Shape[] shapes) { double max = shapes[0].area(); int maxIndex = 0; for (int i = 1; i < shapes.length; i++) { double area = shapes[i].area(); if (area > max) { max = area; maxIndex = i; } } System.out.println("数组中索引为"+maxIndex+"的图形的面积最大,面积为:"+max); } }
步骤六:运行
运行TestShape类,控制台输出结果如下所示:
数组中索引为0的图形的面积最大,面积为:1.2736
观察上述输出结果,可以看出,shapes[0]表示的是圆形,周长相同的情况下,圆形的面积更大些。
本案例中,Square类的完整代码如下所示:
public class Square extends Shape { public Square(double c) { this.c = c; } /** * 计算正方形的面积 */ public double area() { return 0.0625*c*c; } }
Circle类的完整代码如下所示:
public class Circle extends Shape { public Circle(double c) { this.c = c; } /** * 计算圆形的面积 */ public double area() { return 0.0796*c*c; } }
Shape类的完整代码如下所示:
public abstract class Shape { protected double c; public abstract double area(); }
TestShape类的完整代码如下所示:
public class TestShape { public static void main(String[] args) { Shape[] shapes = new Shape[2]; shapes[0] = new Circle(4);//数组中的第一个元素为圆形对象,周长为4 shapes[1] = new Square(4);//数组中的第二个元素为正方形对象,周长为4 maxArea(shapes); } public static void maxArea(Shape[] shapes) { double max = shapes[0].area(); int maxIndex = 0; for (int i = 1; i < shapes.length; i++) { double area = shapes[i].area(); if (area > max) { max = area; maxIndex = i; } } System.out.println("数组中索引为"+maxIndex+"的图形的面积最大,面积为:"+max); } }
本例要求实现银行卡系统的银联接口,详细要求如下:
1. 银联接口,用于描述银联统一制定的规则,该接口提供检测密码方法、取钱方法以及查询余额方法。
2. 工商银行接口,用于描述工商银行发行的卡片功能,在满足银联接口的规则基础上,增加了在线支付功能。
3. 农业银行接口,用于描述中国农业银行发行的卡片功能,在满足银联接口的规则基础上,增加了支付电话费的功能。另外,农行的卡的卡内余额,允许最多透支2000。
4. 实现工商银行接口和农业银行接口,并进行测试。
工行卡的控制台交互效果如图-1所示:
图-1
农行卡的控制台交互效果如图-2所示:
图-2
从图-2中可以看出,农行卡的卡内余额可以为负数。
实现此案例需要按照如下步骤进行。
步骤一:定义银联接口
首先,定义名为UnionPay的银联接口,用于描述银联统一制定的规则;然后,在该接口中定义getBalance方法表示获取余额功能、定义drawMoney表示取钱功能、定义checkPwd表示检查密码功能,代码如下所示:
/** * 接口:用于描述银联统一制定的规则 */ public interface UnionPay { /**查看余额*/ public double getBalance(); /**取钱*/ public boolean drawMoney(double number); /**检查密码*/ public boolean checkPwd(String input); }
步骤二: 定义工商银行接口
定义名为ICBC的接口表示工商银行接口,用于描述中国工商银行发行的卡片功能,该接口需要满足银联接口的功能,因此,继承银联接口;该接口在具备银联接口的功能基础上,要求增加在线支付功能,所以,在该接口中定义payOnline方法,表示此功能,代码如下所示:
/** * 接口:用于描述工商银行发行的卡片功能,在满足 * 银联的规则基础上,添加自己特有的功能 */ public interface ICBC extends UnionPay { /**增加的在线支付功能*/ public void payOnline(double number); }
步骤三:定义农业银行接口
定义名为ABC的接口表示农业银行接口,用于描述中国农业银行发行的卡片功能,该接口需要满足银联接口的功能,因此,需要继承银联接口;该接口在具备银联接口的功能基础上,要求增加支付电话费功能,所以,在该接口中定义payTelBill方法,表示此功能,代码如下所示:
/** * 接口:用于描述中国农业银行发行的卡片功能,在满足 * 银联的规则基础上,添加自己特有的功能 */ public interface ABC extends UnionPay { /**增加支付电话费的功能*/ public boolean payTelBill(String phoneNum,double sum); }
步骤四:定义工商银行接口的实现类
首先,定义为名ICBCImpl的类 ,该类实现ICBC接口;另外,分析问题中的取钱功能,需要对余额信息进行存储,插入卡片以后需要输入密码后才能进行取钱,因此,在ICBCImpl类中定义double类型属性money表示账户余额以及String类型属性pwd表示卡片的密码,代码如下所示:
/** * 类:用于描述工商银行实际发行的卡片 * 该卡片具有的功能来自于继承的已经符合银联规范的ICBC接口 */ public class ICBCImpl implements ICBC { private double money; private String pwd; public ICBCImpl(double money,String pwd){ this.money = money; this.pwd = pwd; } }
步骤五:实现检查密码、获取余额、取款、在线支付功能
在ICBCImpl类实现checkPwd方法、getBalance方法、drawMoney方法以及payOnline方法,代码如下所示:
/** * 类:用于描述工商银行实际发行的卡片 * 该卡片具有的功能来自于继承的已经符合银联规范的ICBC接口 */ public class ICBCImpl implements ICBC { private double money; private String pwd; public ICBCImpl(double money,String pwd){ this.money = money; this.pwd = pwd; } #cold_bold @Override #cold_bold public double getBalance() { #cold_bold return money; #cold_bold } #cold_bold #cold_bold @Override #cold_bold public boolean drawMoney(double number) { #cold_bold if(number <= money){ #cold_bold money -=number; #cold_bold return true; #cold_bold } #cold_bold return false; #cold_bold #cold_bold } #cold_bold #cold_bold @Override #cold_bold public void payOnline(double number) { #cold_bold if(number < money){ #cold_bold money-=number; #cold_bold } #cold_bold } #cold_bold #cold_bold @Override #cold_bold public boolean checkPwd(String input) { #cold_bold if(pwd.equals(input)) #cold_bold return true; #cold_bold else #cold_bold return false; #cold_bold } }
以上四个方法的实现逻辑为:
取钱功能的实现为在当前余额的基础上减去要取的金额,如drawMoney方法的实现。
在线付款功能的实现为当前余额的基础上减去要支付的金额,如payOnline方法的实现。
检查密码功能的实现为检查卡的密码与用户输入的密码是否相等,如果相等返回true,否则返回false,如checkPwd方法的实现。
获取余额功能的实现为类ICBCImpl,类中money属性即表示余额,将其返回即可,如getBalance方法的实现。
步骤六:定义农业银行接口的实现类
实现农业银行接口的过程与实现工行接口的过程类似,实现的过程中注意,农行卡的卡内余额可以透支2000,代码如下所示:
/** * 类:用于描述农业银行实际发行的卡片 * 该卡片具有的功能来自于继承的已经符合银联规范的ABC接口 */ public class ABCImpl implements ABC { /**卡内余额,允许最多透支2000*/ private double balance; /**账号密码*/ private String password; public ABCImpl(double balance,String password){ this.balance = balance; this.password = password; } @Override public double getBalance() { return balance; } @Override public boolean drawMoney(double number) { if((balance-number) >= -2000){ balance-=number; return true; } return false; } @Override public boolean checkPwd(String input) { if(password.equals(input)){ return true; }else{ return false; } } @Override public boolean payTelBill(String phoneNum, double sum) { if(phoneNum.length() == 11 && (balance-sum)>=-2000){ balance-=sum; return true; } return false; } }
步骤七:测试
新建TestUnionPay类,测试银联接口提供的方法,是否成功实现,代码如下所示:
import java.util.Scanner; /** * 测试实现接口后的类的方法调用 */ public class TestUnionPay { public static void main(String[] args) { UnionPay icbc = new ICBCImpl(2000,"123456"); Scanner input = new Scanner(System.in); System.out.println("请输入密码:"); if(icbc.checkPwd(input.next())){ System.out.println("请输入金额:"); double num = Double.parseDouble(input.next()); if(icbc.drawMoney(num)){ System.out.println("取钱成功,卡余额为:"+icbc.getBalance()); } else{ System.out.println("取钱失败"); } }else{ System.out.println("密码错误"); } input.close(); } }
查看上述代码,可以看出以上代码是采用ICBCImpl类来实例化银联接口UnionPay的,当然,也可以使用ABCImpl来实例化银联接口UnionPay,此时,卡内余额是可以透支2000元的。
本案例中,UnionPay接口的完整代码如下所示:
/** * 接口:用于描述银联统一制定的规则 */ public interface UnionPay { /**查看余额*/ public double getBalance(); /**取钱*/ public boolean drawMoney(double number); /**检查密码*/ public boolean checkPwd(String input); }
ICBC接口的完整代码如下所示:
/** * 接口:用于描述工商银行发行的卡片功能,在满足 * 银联的规则基础上,添加自己特有的功能 */ public interface ICBC extends UnionPay { /**增加的在线支付功能*/ public void payOnline(double number); }
ABC接口的完整代码如下所示:
/** * 接口:用于描述中国农业银行发行的卡片功能,在满足 * 银联的规则基础上,添加自己特有的功能 */ public interface ABC extends UnionPay { /**增加支付电话费的功能*/ public boolean payTelBill(String phoneNum,double sum); }
ICBCImpl类的完整代码如下所示:
/** * 类:用于描述工商银行实际发行的卡片 * 该卡片具有的功能来自于继承的已经符合银联规范的ICBC接口 */ public class ICBCImpl implements ICBC { private double money; private String pwd; public ICBCImpl(double money,String pwd){ this.money = money; this.pwd = pwd; } @Override public double getBalance() { return money; } @Override public boolean drawMoney(double number) { if(number <= money){ money -=number; return true; } return false; } @Override public void payOnline(double number) { if(number < money){ money-=number; } } @Override public boolean checkPwd(String input) { if(pwd.equals(input)) return true; else return false; } }
ABCImpl类的完整代码如下所示:
/** * 类:用于描述农业银行实际发行的卡片 * 该卡片具有的功能来自于继承的已经符合银联规范的ABC接口 */ public class ABCImpl implements ABC { /**卡内余额,允许最多透支2000*/ private double balance; /**账号密码*/ private String password; public ABCImpl(double balance,String password){ this.balance = balance; this.password = password; } @Override public double getBalance() { return balance; } @Override public boolean drawMoney(double number) { if((balance-number) >= -2000){ balance-=number; return true; } return false; } @Override public boolean checkPwd(String input) { if(password.equals(input)){ return true; }else{ return false; } } @Override public boolean payTelBill(String phoneNum, double sum) { if(phoneNum.length() == 11 && (balance-sum)>=-2000){ balance-=sum; return true; } return false; } }
TestUnionPay类的完整代码如下所示:
import java.util.Scanner; /** * 测试实现接口后的类的方法调用 */ public class TestUnionPay { public static void main(String[] args) { UnionPay icbc = new ICBCImpl(2000,"123456"); Scanner input = new Scanner(System.in); System.out.println("请输入密码:"); if(icbc.checkPwd(input.next())){ System.out.println("请输入金额:"); double num = Double.parseDouble(input.next()); if(icbc.drawMoney(num)){ System.out.println("取钱成功,卡余额为:"+icbc.getBalance()); } else{ System.out.println("取钱失败"); } }else{ System.out.println("密码错误"); } input.close(); } }