客户信息管理系统----Java实现(以对象数组为主)

这两天除了上课时间之外,一直在看一个“客户信息管理系统”,一套代码敲下来,收获颇丰,下面对这个小的项目(或者说是案例,)进行一个总结吧!

具体的解释以及思路,我写在了代码中间,以注释的形式来表现。

要实现的功能

编写一个客户信息管理系统,实现对于客户基本信息的“增、删、查、改”的操作。

虽然看起来功能都不算难,但是编程的过程中,着实不易。
主要将功能封装在4个类中:

CustomerView:

作为主模块,负责菜单的显示和处理用户操作

CustomerList

作为Customer对象的管理模块,内部用数组管理一组Customer对象,并提供相应的添加、修改、删除和遍历方法,
供CustomerViewer调用

Customer

作为实体对象,用来封装客户信息

CMUtility

CMUtility工具类,将不同的功能封装为方法,就是可以直接通过调用方法使用它的功能,而无需考虑具体的功能实现细节

具体的代码实现如下:(另外在文章本文的末尾附有完整的源代码压缩包,可供下载)

1、CustomerView类:

/*
 * 作为主模块,负责菜单的显示和处理用户操作
 */
/**
 * 
 * @Description 主模块,负责菜单的显示和处理用户操作
 * @author admin
 *
 */
public class CustomerView {
	/*
	 * 实例化一个CustomerList类的对象, 要注意的是:在实例化创建CustomerList类的对象customerList的时候,
	 * 会调用CustomerList类的构造函数,
	 * 也就是我们自己写上去的那个有参(参数为totalcustomer,即:Customer[]数组长度的)构造函数
	 */
	private CustomerList customerList = new CustomerList(10);

	/*
	 * 便于测试------>提供一个当前类的构造器, 以便在创建对象的过程中就给对象数组就产生了一个信息
	 */
	// 构造器
	public CustomerView() {
		Customer customer = new Customer("王涛", '男', 23, "17513312345", "wt@163.com");
		/*
		 * 添加一个客户,将它放在数组当中
		 */
		customerList.addCustomer(customer);
	}

	/*
	 * 显示《客户信息管理软件》界面的方法
	 */
	private void enterMainMenu() {

		boolean isFlag = true;
		while (isFlag) {
			System.out.println("\n----------客户信息管理软件----------");
			System.out.println("            1、添加客户");
			System.out.println("            2、修改客户");
			System.out.println("            3、删除客户");
			System.out.println("            4、客户列表");
			System.out.println("            5、退出\n");
			System.out.print("            请选择(1-5):");

			char menu = CMUtility.readMenuSelection();
			/*
			 * 得到menu之后,到底是哪一个,需要一个分支语句
			 */
			switch (menu) {
			case '1':
				addNewCustomer();
				break;
			case '2':
				modifyCustomer();
				break;
			case '3':
				deleteCustomer();
				break;
			case '4':
				listAllCustomers();
				break;
			case '5':
				/*
				 * 因为没有写退出的方法,可以直接将退出的方法写到这里
				 */
				System.out.print("是否确认退出(Y/N):");
				/*
				 * 调用CMUtility.readConfirmSelection() 将输入的字符串(包容误输入)取第一个值,并且转换为对应的大写字母
				 */
				char isExit = CMUtility.readConfirmSelection();
				if (isExit == 'Y') {
					isFlag = false;
				}
				/*
				 * 如果输入的是N,结束case,就直接回到循环,执行下一次循环了
				 */
			}
		}
	}

	/*
	 * 添加客户的操作
	 */
	private void addNewCustomer() {
		System.out.println("---------------------------添加客户-----------------------------");
		System.out.print("姓名:");
		/*
		 * 读入姓名
		 */
		String name = CMUtility.readString(10);
		System.out.print("性别:");
		char gender = CMUtility.readChar();
		System.out.print("年龄:");
		int age = CMUtility.readInt();
		System.out.print("电话:");
		String phone = CMUtility.readString(13);
		System.out.print("邮箱:");
		String email = CMUtility.readString(30);

		/*
		 * 将上述数据封装到一个对象中,再将这个对象放入customerList[]数组中去
		 */
		Customer customer = new Customer(name, gender, age, phone, email);
		/*
		 * 不一定可以添加成功
		 */
		boolean isSuccess = customerList.addCustomer(customer);
		if (isSuccess) {
			System.out.println("---------------------------添加完成-----------------------------");
		} else {
			System.out.println("-----------------------客户目录已满,添加失败--------------------------");
		}

	}

	/*
	 * 修改客户的操作
	 */
	private void modifyCustomer() {
//		System.out.println("修改客户的操作");
		System.out.println("---------------------------修改客户-----------------------------");
		/*
		 * 声明一个Customer对象:存储查找到的要修改信息的元素的内容 (是一个地址值或者是一个null) 因为是引用数据类型
		 */
		int number;
		Customer cust;
		/*
		 * 不知道循环要执行多少次 具体的循环次数,依据输入的信息而定,如果输入的一直不合法 就一直在这个循环内,提醒用户输入
		 */
		for (;;) {
			/*
			 * 这个循环只有两个出口: 1、输入的number==-1,退出修改的功能 2、break,进入到修改信息的具体功能实现的模块
			 */
			System.out.println("请选择待修改的客户编号(-1退出)");
			number = CMUtility.readInt();// 记录要修改的编号

			if (number == -1) {
				return;// 此时结束此方法,直接回到switch-case中的相应位置
			}
			/*
			 * 如果不是-1,也要输入的合理才可以 调用customerList.getCustomer方法 ------>
			 * 如果合理,就返回对象数组中对应的元素的值(是该元素所存储的对象地址) 如果不合理,根据该函数可知,返回的是null ----------
			 * 需要注意的是,用户输入的number比实际的索引值要 大1
			 */
			cust = customerList.getCustomer(number - 1);
			/*
			 * 判断cust是否靠谱
			 */
			if (cust == null) {
				System.out.println("无法找到指定的客户!");
				// 此时继续提示用户输入要自改的数据对应的编号----继续这个循环的下一轮
			} else {
				// 找到相应编号的客户
				break;// 将相应的操放到这个for循环的外边写
			}
		}
		/*
		 * 因为可以跑到这里的,就一定是通过break额 ---->输入的编号值合法的 所以,在这里编写修改相应信息的代码
		 */
		System.out.println("姓名(" + cust.getName() + "):");
		/*
		 * 如果用户没有直接换行,就以输入的姓名为准 如果用户直接换行,就以cust.getName()得到的值为准
		 */
		// 记录修改后,各个元素应该有的值
		String name = CMUtility.readString(10, cust.getName());
		System.out.println("性别(" + cust.getGender() + "):");
		char gender = CMUtility.readChar(cust.getGender());
		System.out.println("年龄(" + cust.getAge() + "):");
		int age = CMUtility.readInt(cust.getAge());
		System.out.println("电话(" + cust.getPhone() + "):");
		String phone = CMUtility.readString(13, cust.getPhone());
		System.out.println("邮箱(" + cust.getEmail() + "):");
		String email = CMUtility.readString(30, cust.getEmail());

		/*
		 * 将上述数据封装到一个对象中,再将这个对象放入customerList[]数组中去
		 */
		Customer newCust = new Customer(name, gender, age, phone, email);
		/*
		 * number-1 是对应的对象数组的索引值
		 * 
		 * 做替换不一定能够换成,得再加上一个判断
		 */
		boolean isRepalaced = customerList.replaceCustomer(number - 1, newCust);
		if (isRepalaced) {
			System.out.println("---------------------------修改完成-----------------------------");
		}
		// 其实,现编的情况是没有可能会出现的
		else {
			System.out.println("---------------------------修改失败-----------------------------");
		}
	}

	/*
	 * 删除客户的操作
	 */
	private void deleteCustomer() {
		System.out.println("---------------------------删除客户-----------------------------");
		
		int number;
		/*
		 * 此循环只有两个出口:
		 * 1、number==-1,直接接退出删除的功能
		 * 2、最终的number满足删除的要求,实现了break,进入到剩下的部分
		 * (此方法剩下的部分的内容是 :实现对于删除的具体操作
		 * ----实际上也是调用方法来实现的
		 * 调用的是CustomerList的deleteCustomer方法)
		 */
		for(;;) {
			//具有跟修改相似的循环逻辑
			System.out.println("请选择待删除的客户编号(-1退出)");
			number = CMUtility.readInt();//注意:number的有效范围是从1 开始到total
			
			if(number == -1 ) {
				return;
			}
			//不是输入-1,确是是要修改信息
			/*
			 * 注意:number-1才是对应的索引值
			 * 因为用户是从1开始算的
			 * 而java中是从0开始计算的
			 */
			Customer customer = customerList.getCustomer(number - 1);
			/*
			 * 可能找不到指定的客户信息----customer不靠谱
			 * 此时customer的值为null
			 */
			if(customer == null) {
				System.out.println("无法找到指定用户!");
				//此时将结束本次循环,进入下一轮的for循环中去
			} else {
				break;
			}
		}
		
		//找到了指定的客户,开始执行删除操作
		System.out.println("是否确认删除(Y/N)");
		char isDelete = CMUtility.readConfirmSelection();
		/*
		 * 判断是否输入Y或者y
		 * 但是判断的时候只用判断是否为Y即可
		 * 因为调用的CMUtility.readConfirmSelection(),实现了将输入的字符串中的首字符转换为大写的功能
		 */
		if(isDelete == 'Y') {
			boolean deleteSuccess = customerList.deleteCustomer(number-1);
			if(deleteSuccess ) {
				System.out.println("---------------------------删除成功-----------------------------");
			}
//			else {
//				System.out.println("---------------------------删除失败-----------------------------");
//			}//实际上,没有机会执行
		}
		//如果输入的是n----直接退出这个方法,回到switch-case,继而回到主界面
//		else {
//			return;//要不要这个无所谓。因为已经在方法的末尾了
//		}
		
	}

	/*
	 * 显示客户列表的操作
	 */
	private void listAllCustomers() {
		System.out.println("---------------------------客户列表-----------------------------");
		/*
		 * 先判断数组(是对象数组)中存放的有没有数据
		 */
		int total = customerList.getTotal();
		if (total == 0) {
			System.out.println("没有客户记录!");
		} else {
			/*
			 * 找到客户记录
			 */
			System.out.println("编号\t姓名\t性别\t年龄\t电话\t\t邮箱");
			/*
			 * 列出客户记录
			 */
			// 获取到数组中存储到的数据
			Customer[] custs = customerList.getAllCustomers();
			for (int i = 0; i < custs.length; i++) {
				/*
				 * 新造的数组中的每个元素,存储的都是对应的对象的存储地址 也就是一个对象元素
				 */
				Customer cust = custs[i];
				System.out.println(i + 1 + "\t" + cust.getName() + "\t" + cust.getGender() + "\t" + cust.getAge() + "\t"
						+ cust.getPhone() + "\t" + cust.getEmail());
			}

		}

		System.out.println("-------------------------客户列表完成----------------------------");
	}

	public static void main(String[] args) {
		/*
		 * 登陆进去要先显示主菜单 main()方法想要调用显示主菜单的方法 就应该先创建一个当前类的对象
		 */
		CustomerView view = new CustomerView();
		// 显示主菜单
		view.enterMainMenu();

	}

}

2、CustomerList类

/*
 * 作为Customer对象的管理模块,
 * 内部用数组管理一组Customer对象,
 * 并提供相应的添加、修改、删除和遍历方法,
 * 供CustomerViewer调用 
 */
/**
 * 
 * @Description  作为Customer对象的管理模块,内部用数组管理一组Customer对象,
 * @author admin
 *
 */
public class CustomerList {
	//属性
	private Customer[] customers ;//用来保存客户对象的数组
	private int total = 0;//记录已保存客户对象的数量
	/*
	 * total的值是0 ,
	 * 显示初始化为0,或者不写的话,默认的初始化值也是0
	 */
	
	//提供以下构造器、方法
	/*
	 * 构造器
	 * 初始化数组,
	 * 参数totalcustomer表示数组有多长
	 */
	public CustomerList(int totalcustomer) {
		/*
		 * 当创建CustomerList对象的时候,就在这个构造函数中,将数组初始化
		 * 操作数组之前一定要将其初始化
		 */
		customers = new Customer[totalcustomer];
	}
	/*
	 * 增----将指定的客户customer添加到数组中
	 * 添加成功----返回true
	 * 添加失败----返回false(满了就失败了)
	 */
	public boolean addCustomer(Customer customer) {
		/*
		 * 先判断是否满了----满了就添加不进去了
		 */
		if(total >= customers.length) {
			return false;//已经满了
		}
		/*
		 * 没有满的话,直接添加
		 * ----添加的话,先放到数组的索引所指的位置,再将索引值 +1
		 */
//		customers[total] = customer;
//		total++;
		//或者
		customers[total++] = customer;
		return true;
	}
	/*
	 * 修改指定位置上的客户信息
	 * ----形参是两个值,一个是要修改的下标索引;另一个是数组对应的元素要改的值
	 */
	public boolean replaceCustomer(int index,Customer cust) {
		/*
		 * index决定了是否可以修改
		 */
		if(index < 0 ||index >= total) {
			return false;
		}
		customers[index] = cust;
		/*
		 * 这里改的是指针
		 * 原因在于:通过构造器创造出来的数组,其数组元素是Customer,
		 * 而Customer又是一个对象,
		 * ---->所以又new出来Customer对象,每个对象的地址值给了存储它的数组元素
		 * -------->数组中的每个位置放置的是:一个Customer类型的对象的地址
		 * -----------------
		 * 现在做的replace操作,就是:
		 * 又new出来一个对象,它的地址为cust
		 * 现在需要将数组中索引值为index的元素中存储的值,改为cust
		 * (使index的索引,指向地址cust存储的Customer对象)
		 * 而原来的index处存储的那个地址所指向的Customer对象,因为没有指针指向,就被当做垃圾销毁
		 */
		return true;
	}
	/*
	 * 删除指定索引位置上的客户
	 */
	public boolean deleteCustomer(int index) {
		/*
		 * index决定了是否可以删除,跟修改一样,存在了才可以删除
		 */
		if(index < 0 ||index >= total) {
			return false;
		}
		/*
		 * 删掉的如果是位于中间位置的索引的话,不能直接将该索引对应的值置为null
		 * 应将要删掉的索引的,后边的元素往前移,将现有的最后一个存储数据的索引值置为null
		 * ------>这是因为数组是一段连续的空间,不允许中间空着,后边放别的
		 */
		/*
		 * 写一个循环,将index小后边的元素一个个往前移
		 * ---->需要注意的是:total记录的是元素的个数,
		 * 即:比最后一个存储了元素的索引 大1
		 * 但是需要注意的是,因为i表示的是将i+1的元素放到i上,所以i的最大值为total-2
		 * 如果在这里不注意的话,容易产生下标越界的情况
		 */
		for(int i = index;i < total - 1;i++) {
			customers[i] = customers[i + 1];//数组元素前移
		}
		//最后有数据的元素需要置null
//		customers[total - 1] = null;
//		total--;//当前存储元素的索引最大值,也应该作出相应的变化
		//或者合并:
		customers[--total] = null;
		return true;
	}
	/*
	 * 查----获取所有的客户信息
	 * 返回的是Customer[]类型的数组的首地址
	 */
	public Customer[] getAllCustomers() {
		/*
		 * 因为已有的数组中可能有空的元素
		 * 所以不能直接返回已有的数组
		 * ---->应该重新造一个元素来存储
		 */
		Customer[] custs = new Customer[total];
		//数组的复制
		for(int i = 0;i < custs.length;i++) {
			/*
			 * 并不是把每一个Customer对象都复制一份,复制的只是Customer[]数组中存储的地址值
			 */
			custs[i] = customers[i];
		}
		return custs;
	}
	/*
	 * 查----查循一个,具体查哪一个的话,按照索引判断
	 * 获取指定位置上的客户
	 * 返回值的类型是:Customer类的一个对象,
	 * ----也即:Customer[]数值中的一个元素(虽然返回的是一个地址值,但是这个地址值指向的是一个Customer类的对象)
	 * 又因为引用类型的默认初始化值为null,所以如果找不到的话,返回一个null即可
	 */
	public Customer getCustomer(int index) {
		/*
		 * index这个索引值,不一定靠谱,因为这个位置上不一定存储有元素
		 */
		if(index < 0 || index >= total) {
			return null;//找不到
		}
		return customers[index];		
	}
	/*
	 * 获取已经存储的客户的数量
	 */
	public int getTotal() {
		/*
		 * 因为total的值,代表的是所有的客户总数
		 * 也是下一个将要存储的数组元素的索引值
		 */
		return total;
	}
}

3、Customer类

/*
 * 作为实体对象,用来封装客户信息
 */
/**
 * 
 * @Description
 * @author admin
 *
 */
public class Customer {
	private String name;//客户姓名
	private char gender;//性别
	private int age;//年龄
	private String phone;//电话号码
	private String email;//电子邮箱
	
	//getxx、setxx方法
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public char getGender() {
		return gender;
	}
	public void setGender(char gender) {
		this.gender = gender;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getPhone() {
		return phone;
	}
	public void setPhone(String phone) {
		this.phone = phone;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	
	
	//提供构造器
	//先写一个空参的
	public Customer() {
		
	}
	//再写一个全参的
	public Customer(String name, char gender, int age, String phone, String email) {
		this.name = name;
		this.gender = gender;
		this.age = age;
		this.phone = phone;
		this.email = email;
	}
}
//实质上就是一个Javabean

4、CMUtility类

/* 
* defaultValue
 * ----如果用户不输入字符而直接回车,方法将以defaultValue作为返回值
 * 在修改客户时调用
 */
import java.util.*;
/*
 * CMUtility工具类,
 * 将不同的功能封装为方法,
 * 就是可以直接通过调用方法使用它的功能,而无需考虑具体的功能实现细节
 */
public class CMUtility {
	private static Scanner scanner = new Scanner(System.in);
	/*
	 * 用于界面菜单的选择
	 * 该方法读取键盘:
	 * 如果用户键入‘1’-‘5’中的任意字符,则方法返回。
	 * 返回值为用户所选择的功能对应的字符
	 */
	public static char readMenuSelection() {
		char c;
		/*
		 * 设置循环的结束条件是:
		 * 读取到有意义的字符
		 */
		for(;;) {
			String str = readKeyBoard(1,false);
			c = str.charAt(0);
			if(c != '1' && c != '2' && 
					c != '3' && c != '4' && c != '5') {
				System.out.print("选择错误,请重新输入:");
			}else break;
		}
		return c;
	}
	/*
	 * 从键盘读取一个字符,并将其作为方法的返回值
	 * 这里读取的是性别
	 * ----
	 * 与下边修改性别的方法构成重载
	 */
	public static char readChar() {
		String str = readKeyBoard(1,false);
		return str.charAt(0);
	}
	/*
	 * 从键盘读取一个字符,并将其作为方法的返回值
	 * 如果用户不输入字符而直接回车,方法将以defaultValue 作为返回值
	 * 修改性别的时候用到
	 * ------
	 * 如果用户没有输入的话,就拿形参的值再去填充,把它作为默认的值去返回
	 */
	public static char readChar(char defaultValue) {
		String str = readKeyBoard(1,true);
		return (str.length() == 0 )? defaultValue:str.charAt(0);
	}
	/*
	 * 从键盘读取一个长度不超过2位的整数
	 * 读取的是年龄
	 * 
	 */
	public static int readInt() {
		int n;
		for(;;) {
			String str = readKeyBoard(2,false);
			try {
				n = Integer.parseInt(str);
				break;
			} catch (NumberFormatException e) {
				System.out.println("数字输入错误,请重新输入:");
			}
		}
		return n;
	}
	/*
	 * 从键盘读取一个长度不超过2位的整数,并将其作为方法 的返回值
	 * 如果用户不输入字符而直接回车,方法将以defaultValue 作为返回值
	 * 在修改年龄的啥时候用到
	 * 
	 */
	public static int readInt(int defaultValue) {
		int n;
		for(;;) {
			String str = readKeyBoard(2,true);
			if(str.equals("")) {
				return defaultValue;
			}
			try {
				n = Integer.parseInt(str);
				break;
			} catch (NumberFormatException e) {
				System.out.println("数字输入错误,请重新输入:");
			}
		}
		return n;
	}
	/*
	 * 从键盘读取一个长度不超过limit的字符串,并将其作为方法的返回值
	 * 读取的是电话号码
	 */
	public static String readString(int limit) {
		return readKeyBoard(limit,false);
	}
	/*
	 * 从键盘读取一个长度不超过limit的字符串,将其作为方法的返回值
	 * 如果用户不输入字符而直接回车,方法将以defaultValue 作为返回值
	 * 修改的时候用到的方法
	 * 
	 */
	public static String readString(int limit,String defaultValue) {
		String str = readKeyBoard(limit,true);
		return str.equals("")? defaultValue : str;
	}
	/*
	 * 用于确认选择的输入。该方法从键盘读取‘Y’或‘N',并将其作为方法的返回值
	 * ----用于删除和退出的时候的  再次确认
	 * 
	 */
	public static char readConfirmSelection() {
		/*
		 * 存储从键盘读入的字符串的第一个值(y 或者 n,或者错误的输入),
		 * 并在确定输入的是y 或者 n,的情况下,返回对应的大写字母,以便进行比对
		 */
		char c;
		/*
		 * 循环的结束条件为空
		 * 真正判断----结束循环的条件,在循环体中,
		 * 何时结束循环,由输入的情况而定
		 */
		for(;;) {
			/*
			 * 将从键盘读取到的字符串,转换成大写再进行判断
			 * 这样不论输入‘Y’还是‘y’,都可以使得正确退出
			 */
			String str = readKeyBoard(1,false).toUpperCase();
			/*
			 * 读取的是str中的第一个字符
			 * 这样可以排除用户输入多余字符,而不能使程序正常结束的情况
			 */
			c = str.charAt(0);
			if(c == 'Y' || c == 'N') {
				break;
			} else {
				System.out.println("选择错误,请重新输入:");
			}
		}
		return c;
	}
	
	private static String readKeyBoard(int limit,boolean blankReturn) {
		String line = "";
		
		while(scanner.hasNextLine()) {
			/*
			 * 从键盘读取的字符串,赋值给line
			 */
			line = scanner.nextLine();
			if(line.length() == 0) {
				/*
				 * 如果line(从键盘读取到的字符串的长度为0----没有读入字符串)
				 */
				if(blankReturn) {
					return line;
				} else {
					continue;
				}
			}
				
				if(line.length() < 1 || line.length() > limit) {
					System.out.print("输入长度(不大于"+limit+")错误,请重新输入: ");
					continue;
				}
				break;
			}
			return line;
		}
	}


源代码可以在这里下载:
  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值