Top

JAVA OOP DAY05

  1. 根据周长计算不同形状图形的面积
  2. 银行卡系统(实现银联接口)

1 根据周长计算不同形状图形的面积

1.1 问题

根据周长计算不同形状图形的面积,详细要求如下:

1. 计算多种图形的面积,并比较各种图形面积的最大值。

2. 使用抽象类及其子类的方式实现本案例。

3. 本案例以圆形和正方形为例。

注:正方形的面积公式为:0.0625*c*c。圆形的面积公式为:0.0796*c*c,其中,c表示图形的周长。

1.2 方案

分析问题中的描述,可以得出如下解决方案:

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[]数组类型,该参数中可以存储正方形、圆形、或是其它图形。

1.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:定义类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]表示的是圆形,周长相同的情况下,圆形的面积更大些。

1.4 完整代码

本案例中,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);
	}
}

2 银行卡系统(实现银联接口)

2.1 问题

本例要求实现银行卡系统的银联接口,详细要求如下:

1. 银联接口,用于描述银联统一制定的规则,该接口提供检测密码方法、取钱方法以及查询余额方法。

2. 工商银行接口,用于描述工商银行发行的卡片功能,在满足银联接口的规则基础上,增加了在线支付功能。

3. 农业银行接口,用于描述中国农业银行发行的卡片功能,在满足银联接口的规则基础上,增加了支付电话费的功能。另外,农行的卡的卡内余额,允许最多透支2000。

4. 实现工商银行接口和农业银行接口,并进行测试。

工行卡的控制台交互效果如图-1所示:

图-1

农行卡的控制台交互效果如图-2所示:

图-2

从图-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元的。

2.3 完整代码

本案例中,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();
	}
}