Java练手小项目——BMI计算器

最近有一个减肥的朋友想要知道自己的BMI是多少,问我能不能给他做一个计算BMI的工具(无中生友)。于是用Java简单写了一个。一起来看看吧。

身体质量指数是BMI指数(身体质量指数,简称体质指数),是目前国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。
计算公式为:BMI=体重(千克)除以身高(米)的平方。

为了方便使用我把整个小项目整合成了一个文件,复制到记事本里可以直接运行。

import java.io.*;
/**
 * 本程序实现简单的BMI计算器。
 * 	|-实现了用户键盘输入数据;
 * 	|-实现了BMI保留一位小数点
 * 	|-实现了Java标准输出到文件
 * 	|-实现了工厂设计模式,减少耦合
 * 	|-添加了对异常的处理
 * @author chuchu
 *
 */
public class Test {
     
	public static void main(String[] args) {
     
		new Menu();
	}
}

class Menu {
     
	private Person per = null;
	private BMIService bs = null;
	private double BMI = 0.0;
	private PrintUtil out = null;

	public Menu() {
     
		this.show();
	}

	public void show() {
     
		System.out.println("***欢迎使用BMI计算器,请输入相关信息***");
		String name = InputUtil.getInfo("请输入姓名:");
		int age = Integer.parseInt(InputUtil.getInfo("请输入年龄:"));
		double height = Double.parseDouble(InputUtil.getInfo("请输入身高(米):"));
		double weight = Double.parseDouble(InputUtil.getInfo("请输入体重(kg):"));

		bs = Factory.getInstance();
		double b = bs.getBMI(height, weight);
		BMI = Math.round(b * 100) / 100;
		String Evl = bs.getEvaluate(BMI);
		per = new Person(name, age, height, weight, BMI, Evl);
		System.out.println("***信息创建成功***");
		System.out.println("您的BMI为:" + BMI);
		System.out.println("您的身体状况:" + Evl);
		System.out.println("正在将您的文件输出为文本。。。。");
		out = Factory.getPrintInstance(per);
		if (out.print())
			System.out.println("文件输出成功,地址为" + out.getPATH());
		else {
     
			System.out.println("文件输出失败!");
			show();
		}
	}
}

class Factory {
     
	private Factory() {
     
	}

	public static BMIService getInstance() {
     
		return new BMIServiceImpl();
	}

	public static PrintUtil getPrintInstance(Person per) {
     
		return new PrintUtil(per);
	}
}

interface BMIService {
     
	public double getBMI(double height, double weight);

	public String getEvaluate(double BMI);
}

class BMIServiceImpl implements BMIService {
     
	private static final String THIN = "您的体型偏瘦,请增加营养摄入,加强锻炼!";
	private static final String NORMAL = "您的体型正常,请继续保持!";
	private static final String FATTY = "您已偏胖,请改变不健康的生活习惯,加强锻炼!";
	private static final String OBESITY = "您的体型肥胖,相关疾病风险显著增加!";

	@Override
	public double getBMI(double height, double weight) {
     
		return weight / (height * height);
	}

	@Override
	public String getEvaluate(double BMI) {
     
		if (BMI < 18.5)
			return THIN;
		else if (BMI < 24)
			return NORMAL;
		else if (BMI < 28)
			return FATTY;
		else if (28 < BMI)
			return OBESITY;
		else
			return "数据有误,请重新输入相关信息!";
	}

}

class InputUtil {
     
	private static final BufferedReader BR = new BufferedReader(new InputStreamReader(System.in));

	private InputUtil() {
     
	}

	public static String getInfo(String promot) {
     
		String str = null;
		boolean flag = true;
		while (flag) {
     
			try {
     
				System.out.println(promot);
				str = BR.readLine();
				if ("".equals(str) || str == null)
					System.out.println("输入的信息不能为空,请检查后重新输入!");
				else
					flag = false;
			} catch (IOException e) {
     
				e.printStackTrace();
			}
		}
		return str;
	}
}

class PrintUtil {
     
	private Person per;

	public PrintUtil(Person per) {
     
		this.per = per;
	}

	public boolean print() {
     
		OutputStream os = null;
		try {
     
			os = new FileOutputStream(new File("D:" + File.separator + per.getName() + "的评测报告.txt"));
			os.write(("姓名:" + per.getName() + "\n").getBytes());
			os.write(("年龄:" + per.getAge() + "\n").getBytes());
			os.write(("身高:" + per.getHeight() + "\n").getBytes());
			os.write(("体重:" + per.getWeight() + "\n").getBytes());
			os.write(("BMI:" + per.getBMI() + "\n").getBytes());
			os.write(("健康评测:" + per.getEvl() + "\n").getBytes());
			return true;
		} catch (Exception e) {
     
			e.printStackTrace();
			return false;
		} finally {
     
			try {
     
				os.close();
			} catch (IOException e) {
     
				e.printStackTrace();
			}
		}
	}

	public String getPATH() {
     
		return "D:" + File.separator + per.getName() + "的评测报告.txt";
	}
}

class Person {
     
	private String name;
	private int age;
	private double height; // kg
	private double weight; // m
	private double BMI;
	private String Evl;

	public Person(String name, int age, double height, double weight, double bMI, String evl) {
     
		this.name = name;
		this.age = age;
		this.height = height;
		this.weight = weight;
		BMI = bMI;
		Evl = evl;
	}

	public String getName() {
     
		return name;
	}

	public void setName(String name) {
     
		this.name = name;
	}

	public int getAge() {
     
		return age;
	}

	public void setAge(int age) {
     
		this.age = age;
	}

	public double getHeight() {
     
		return height;
	}

	public void setHeight(double height) {
     
		this.height = height;
	}

	public double getWeight() {
     
		return weight;
	}

	public void setWeight(double weight) {
     
		this.weight = weight;
	}

	public void setBMI(double bMI) {
     
		BMI = bMI;
	}

	public void setEvl(String evl) {
     
		Evl = evl;
	}

	public double getBMI() {
     
		return BMI;
	}

	public String getEvl() {
     
		return Evl;
	}

}

主类设计思路

整个程序的设计思路是通过伪菜单界面的方式提醒用户一次输入数据,计算出来结果之后将其返回,并利用Java的输入输出流保存文件到特定的位置。既然是伪菜单界面,那么必不可少的就是写一个Menu类来作为整个程序的入口。

public class Test {
     
	public static void main(String[] args) {
     
		new Menu();
	}
}

class Menu {
     
	private Person per = null;
	private BMIService bs = null;
	private double BMI = 0.0;
	private PrintUtil out = null;

	public Menu() {
     
		this.show();
	}

	public void show() {
     
		System.out.println("***欢迎使用BMI计算器,请输入相关信息***");
		String name = InputUtil.getInfo("请输入姓名:");
		int age = Integer.parseInt(InputUtil.getInfo("请输入年龄:"));
		double height = Double.parseDouble(InputUtil.getInfo("请输入身高(米):"));
		double weight = Double.parseDouble(InputUtil.getInfo("请输入体重(kg):"));

		bs = Factory.getInstance();
		double b = bs.getBMI(height, weight);
		BMI = Math.round(b * 100) / 100;
		String Evl = bs.getEvaluate(BMI);
		per = new Person(name, age, height, weight, BMI, Evl);
		System.out.println("***信息创建成功***");
		System.out.println("您的BMI为:" + BMI);
		System.out.println("您的身体状况:" + Evl);
		System.out.println("正在将您的文件输出为文本。。。。");
		out = Factory.getPrintInstance(per);
		if (out.print())
			System.out.println("文件输出成功,地址为" + out.getPATH());
		else {
     
			System.out.println("文件输出失败!");
			show();
		}
	}
}

主方法非常简单,就是一句话,生成一个匿名的Menu类对象,调用Menu无参构造方法。然后依次显示提示语句。

输入流输出流设计

既然要引导依次输入不同的数据,那么就想到我们可以使用System.in实现键盘输入。每次要输入的内容又不同,我们可以将提示信息作为一个字符串传入到输入方法中,并将获取到的数据返回。
而输出流,本来计划要用Hutool的jar包,里面封装了非常好用的输出Map对象的方法。但是考虑到要将整个程序打包成一个文件发给我的朋友,还是决定自己写。于是,我将Person类对象作为一个参数传入到输出工具类之中。这个设计其实不好,因为工具类应该是私有构造的,通过调用不同的静态方法执行相应的功能,Person类对象应该作为参数传入到print()方法中,而不是作为类的私有属性以构造方法参数的形式传入。但是当时写的时候犯困就胡乱写成这个样子。

class InputUtil {
     
	private static final BufferedReader BR = new BufferedReader(new InputStreamReader(System.in));

	private InputUtil() {
     
	}

	public static String getInfo(String promot) {
     
		String str = null;
		boolean flag = true;
		while (flag) {
     
			try {
     
				System.out.println(promot);
				str = BR.readLine();
				if ("".equals(str) || str == null)
					System.out.println("输入的信息不能为空,请检查后重新输入!");
				else
					flag = false;
			} catch (IOException e) {
     
				e.printStackTrace();
			}
		}
		return str;
	}
}

class PrintUtil {
     
	private Person per;

	public PrintUtil(Person per) {
     
		this.per = per;
	}

	public boolean print() {
     
		OutputStream os = null;
		try {
     
			os = new FileOutputStream(new File("D:" + File.separator + per.getName() + "的评测报告.txt"));
			os.write(("姓名:" + per.getName() + "\n").getBytes());
			os.write(("年龄:" + per.getAge() + "\n").getBytes());
			os.write(("身高:" + per.getHeight() + "\n").getBytes());
			os.write(("体重:" + per.getWeight() + "\n").getBytes());
			os.write(("BMI:" + per.getBMI() + "\n").getBytes());
			os.write(("健康评测:" + per.getEvl() + "\n").getBytes());
			return true;
		} catch (Exception e) {
     
			e.printStackTrace();
			return false;
		} finally {
     
			try {
     
				os.close();
			} catch (IOException e) {
     
				e.printStackTrace();
			}
		}
	}

	public String getPATH() {
     
		return "D:" + File.separator + per.getName() + "的评测报告.txt";
	}
}

接口与服务类设计

其实对于计算一个BMI这种简单到只要一行return语句的业务来说,只需要在Person类之中的getBMI()方法的返回值写就可以解决。但是还是想按照标准的流程来进行开发,于是将其专门写了一个接口和接口实现类。在获取健康评价环节,我将几个要返回的评价设置成了常量,放在程序最上边,方便日后的修改。

class Factory {
     
	private Factory() {
     
	}

	public static BMIService getInstance() {
     
		return new BMIServiceImpl();
	}

	public static PrintUtil getPrintInstance(Person per) {
     
		return new PrintUtil(per);
	}
}

interface BMIService {
     
	public double getBMI(double height, double weight);

	public String getEvaluate(double BMI);
}

class BMIServiceImpl implements BMIService {
     
	private static final String THIN = "您的体型偏瘦,请增加营养摄入,加强锻炼!";
	private static final String NORMAL = "您的体型正常,请继续保持!";
	private static final String FATTY = "您已偏胖,请改变不健康的生活习惯,加强锻炼!";
	private static final String OBESITY = "您的体型肥胖,相关疾病风险显著增加!";

	@Override
	public double getBMI(double height, double weight) {
     
		return weight / (height * height);
	}

	@Override
	public String getEvaluate(double BMI) {
     
		if (BMI < 18.5)
			return THIN;
		else if (BMI < 24)
			return NORMAL;
		else if (BMI < 28)
			return FATTY;
		else if (28 < BMI)
			return OBESITY;
		else
			return "数据有误,请重新输入相关信息!";
	}

}

实体类

这里其实就没什么好说的了,就是最简单的简单Java类,实现构造,getter,setter方法。

class Person {
     
	private String name;
	private int age;
	private double height; // kg
	private double weight; // m
	private double BMI;
	private String Evl;

	public Person(String name, int age, double height, double weight, double bMI, String evl) {
     
		this.name = name;
		this.age = age;
		this.height = height;
		this.weight = weight;
		BMI = bMI;
		Evl = evl;
	}

	public String getName() {
     
		return name;
	}

	public void setName(String name) {
     
		this.name = name;
	}

	public int getAge() {
     
		return age;
	}

	public void setAge(int age) {
     
		this.age = age;
	}

	public double getHeight() {
     
		return height;
	}

	public void setHeight(double height) {
     
		this.height = height;
	}

	public double getWeight() {
     
		return weight;
	}

	public void setWeight(double weight) {
     
		this.weight = weight;
	}

	public void setBMI(double bMI) {
     
		BMI = bMI;
	}

	public void setEvl(String evl) {
     
		Evl = evl;
	}

	public double getBMI() {
     
		return BMI;
	}

	public String getEvl() {
     
		return Evl;
	}

}

本次的文章就到这里啦,其实不是什么复杂的业务,闲暇时间练手还是不错的。

你可能感兴趣的:(Java学习日记,java,编程语言,小程序)