1. 购物系统的需求分析和类划分
购物系统本身是一个十分复杂的系统,有很多细节问题如果深究会更加复杂,并且一般购物系统都是网页类型的,要有一个友好的界面,但是作为一个简单项目,该项目只是为了给JAVA初学者介绍一下开发的基本思想,以及面向对象时应该怎样去设计框架和实现流程,所以只是基于eclipse开发的一个简单的项目,并没有GUI的参与,并且很多细节问题作为后续研究,整体的设计比较简单,但是足以说明很多设计思想和设计理念,那么下面对基本的需求进行分析。
作为一个简单的购物系统,至少需要具备以下功能(这些功能分布在不同级的菜单中):
(1)用户登录功能、用户账号密码修改功能,暂时不提供注册功能;
(2)用户成功登录后,需要具备客户信息的管理功能、购物结算功能以及一些抽奖活动等;
(3)客户信息管理功能下面又可以分出很多功能,比如说:查询、修改、增加等;
(4)购物结算功能下面又可以分出很多功能,比如说:商品选购、付款、账单等;
(5)抽奖活动下面又可以设计出多种的抽奖形式,从而进一步划分为许多新的功能模块。
(6)在一级菜单中要提供退出系统的功能,在二级菜单中要提供注销登录的功能,其他级菜单都要能够返回上一级菜单。
上面的这些功能都是一些比较基本的功能,那么如果按照面向流程的思想来设计,就会划分很多功能模块,然后按照流程一步步走就行,但是现在我们采用面向对象的思想来设计,那么应该如何考虑设计框架呢?面向对象的主要思想就是将一些需求抽象为许多类,然后建立这些类之间的联系,通过不同类之间的协同合作,就可以实现所有的功能。所以,现在的主要任务就是如何合理地抽象出这些类,以及这些类要实现什么功能,类之间的联系又是什么?下面通过本次设计的结构对这一过程进行分析。
(1)StartSMS类:用于系统的启动。我们的系统肯定需要一个启动类,这个类里面包含了main方法,用来启动这个系统,这个类是最顶层的,所以不能牵涉太多底层的细节实现,只需要实现一些顶层的基本流程就行,主要还是要调用底层其他类的一些方法来实现功能。
(2)Data类:用来存放我们的所有数据信息,本次设计主要存放的是已经预存的一些可供购买的商品信息和已经注册的会员信息。为什么需要这个类呢?大家想一想,在面向对象的设计中,我们的数据比较多,肯定不能零散地到处定义、任意修改,这样会使得系统的聚合程度太低,容易出现很多错误,并且难以进行后期功能扩展和错误修改,所以我们要把用到的一些公有的数据进行归类,然后放在一个类中,并且在该类中提供对这些数据进行操作的方法。
(3)Menu类:用于显示及处理各级菜单。既然我们设计的是一个购物系统,那么即使再简单,也需要一个基本的菜单,用来和用户进行交互,由于菜单的比较多,并且各级菜单之间层层相连,所以我们需要对菜单进行统一管理,故而出现了菜单类。注意,这里的菜单只是一些顶层的菜单显示和基本的功能调用,具体底层的算法还是需要更加底层的类来实现的。
(4)Manager类:用于存储用户的账户和密码。既然我们需要用户登录,那么肯定需要一个单独的类来管理用户的账户和密码,从而使系统的独立性更强一些。本次设计的用户只有一个账户和密码,只允许修改账户和密码,但是不允许注册。
(5)VerifyEqual类:用于验证登录信息。这个类相当于是把登录这项功能抽象成了一个类,这个实现其实并不是非常必要,但是为了使得系统功能划分更加清晰,所以设计了此类,用来对登录信息和已有的账户和密码进行校验,从而给出校验结果。
(6)CustManagement类:用于客户信息的管理,该类实现了底层的一些功能,比如说查询、修改、增加等。当我们进入到客户信息管理这个菜单的时候,肯定需要对客户信息进行许多操作,为了方便管理这些操作,并考虑到后续的扩展性,这里把客户信息管理的所有功能都抽象出来,放在此类中,上一级菜单通过调用该类中的方法实现客户信息的管理。
(7)Pay类:用于处理购物和结算操作。该类和上面的类存在的原理基本一致,当客户选择进行购物的时候,肯定要有很多操作,比如说买什么、多少钱、付款、找零等,这些功能比较零碎,所以我们对其进行集中管理,从而抽象出该类,对购物和结算的菜单选项的底层算法进行实现,上一级菜单通过调用该类的方法实现购物和结算功能,并且可以返回上一级菜单。
(8)GiftManagement类:用于处理抽奖活动的相关功能。这个类和(6)、(7)中的类存在的理由基本一致,该类对抽奖活动进行了统一管理,上一级菜单只需要通过调用该类的方法就可以实现抽奖的功能。
(9)Gift类:用于管理礼物。既然设计了抽奖环节,那么肯定需要礼物,那么我们会给出什么样的礼物呢,我们总不能每一样礼物都详细列出来吧,这样十分冗余,也很麻烦,所以我们干脆抽象出一个礼物类,把礼物的一些属性:礼物名称和价格等保存成该类的成员变量,然后就可以很方便的管理该类,需要什么样的礼物就直接新建一个礼物对象,然后对该对象的属性进行修改和管理即可,这样的实现类似于一个接口,但是又和接口完全不一样,功能差不多。
总之,上面的类都是经过一些功能模块划分后抽象出来的,有些地方也并不一定合理,主要还是需要看需求,根据不同的需求制定不同的方案。在这里,我想就”Gift类“再强调一点,这个类的设计十分符合面向对象的思想,举个例子来看,如果购物系统中需要很多礼物,比如手机、电脑、移动电源等,那么如果我们一个个写这些礼物,会使得系统代码十分冗余,因为礼物的属性基本一样,所以我们就可以抽象成一个类,从而在需要什么礼物的时候只定义一个对象,然后赋予一定的属性即可,比如需要手机、电脑,那么我们只需要new一个Gift类的对象,然后在需要手机的时候设置其属性为手机,在需要电脑的时候设置其属性为电脑,需要什么设置什么即可,这样就使得我们的代码得到了简化,也使得结构比较清晰。在更为复杂的系统中,其实礼物用接口来实现更为合理,这样就可以根据该接口实现不同的礼物类,从而满足不同的需求,就类似于我们的电脑上的USB接口,只需要这个接口,我们就可以插上很多各种各样的外围设备,道理差不多。
2. 购物系统的类之间的关系和流程(用图示法表示)
下图是我用Microsoft Office Visio 2003画图工具画出的这9个类之间的关系。
从上图中可以清晰地看出来各类之间的关系,大致关系和流程如下所述:
(1)StartSMS类是启动类,内含main方法,这个类里面定义了VerifyEqual类和Data类的对象,用来存储数据和验证信息,同时Data类中包含了Manager类,用来存储预存的用户账号信息,然后在main方法中通过一定的逻辑,去调用Menu类中的showLoginMenu()方法,用于处理一级菜单---登录修改流程;
(2)如果登录成功,就调用Menu类中的showMainMenu()方法,用于处理二级菜单---购物系统的主流程,如果登录失败3次,就直接退出系统;
(3)在Menu类中的showMainMenu()方法中,通过选择不同的二级菜单选项,从而调用Menu类中的showCustMMenu()方法来处理客户信息管理流程或者调用Menu类中的showSendMenu()方法来处理抽奖活动流程,亦或者调用Pay类中的calcPrice()方法来处理购物结算流程;
(4)如果选择了二级菜单中的客户信息管理选项,那么就会调用Menu类中的showCustMMenu()方法,这个方法会调用CustManagement类中的各种方法,用以处理客户信息管理的不同操作;
(5)如果选择了二级菜单中的购物结算选项,那么就会调用Pay类中的calcPrice()方法,从而处理购物结算的流程,注意在Pay类中的getDiscount()方法是用来根据客户会员信息来计算打折率的;
(6)如果选择了二级菜单中的真情回馈选项,即抽奖活动,那么就会调用Menu类中的showSendMenu()方法,这个方法会调用GiftManagement类中的各种方法,用以处理抽奖活动的不同操作;
注意到在CustManagement类和GiftManagement类中都有一个returnLastMenu()方法,该方法是用来返回上一级菜单使用的。
3. 代码实现
需要说明的一点是这些代码都应该放在cn.itcast包下。
3.1 StartSMS类
- package cn.itcast;
- import java.util.Scanner;
- /**
- * 该类是这个系统的主方法类,用于启动购物系统
- *
- * @author
- *
- */
- public class StartSMS {
- /**
- * 空构造方法
- *
- */
- public StartSMS() {
- }
- /**
- * 系统主方法
- *
- * @param args
- */
- public static void main(String args[]) {
- // 创建已有的数据类的对象,并初始化已有的商品信息和顾客信息
- Data data = new Data();
- data.initial();
- // 创建菜单类的对象
- Menu menu = new Menu();
- // 这里将初始化的已有数据信息送给了菜单对象
- menu.setData(
- data.goodsName,
- data.goodsPrice,
- data.custNo,
- data.custBirth,
- data.custScore);
- // 显示一级菜单,即登录界面
- menu.showLoginMenu();
- // 该标志用来判断是否发生了系统操作错误,当操作不当的时候flag为假,从而退出系统,默认为无错误
- boolean flag = true;
- // 处理整个系统的流程
- do {
- // 发生操作错误,退出系统
- if (!flag)
- break;
- // 创建验证用户登录的账户和密码是否正确的类的对象,这里只创建对象,并没有执行验证方法
- VerifyEqual verifyequal = new VerifyEqual();
- // 输入一级菜单中的选择
- Scanner scanner = new Scanner(System.in);
- int i = scanner.nextInt();
- // 根据用户对一级菜单的选择做出不同的响应,注意这里就是经典的switch-case的用法
- switch (i) {
- case 1: // 用户选择"登录系统"
- // 定义计数器,表示用户最多只能尝试3次,3次输入错误直接退出系统
- int j = 3;
- // 处理登录系统的流程
- do {
- if (verifyequal.verify(data.manager.username,
- data.manager.password)) {
- // 用户登录成功,显示购物二级菜单!!!
- menu.showMainMenu();
- break;
- }
- if (j != 1) {
- // 用户输入有误,还没有达到3次,允许重新输入
- System.out.println("\n用户名和密码不匹配,请重新输入:");
- } else {
- // 3次尝试结束,设置退出标志,并退出do-while循环
- System.out.println("\n您没有权限进入系统!谢谢!");
- flag = false;
- break;
- }
- // 每输入一次将计数器减1,用于表示已经尝试了多少次
- j--;
- } while (true);
- break;
- case 2: // 用户选择"更改管理员信息"
- if (verifyequal.verify(data.manager.username,
- data.manager.password)) {
- // 输入新信息前要先验证原来的信息,此处表示已经验证成功
- System.out.print("请输入新的用户名:");
- data.manager.username = scanner.next();
- System.out.print("请输入新的密码:");
- data.manager.password = scanner.next();
- System.out.println("用户名和密码已更改!");
- // 信息更改成功,选择下一步的操作
- System.out.println("\n请选择,输入数字:");
- } else {
- // 信息验证失败,设置退出标志
- System.out.println("抱歉,你没有权限修改!");
- flag = false;
- }
- break;
- case 3: // 用户选择"退出"
- System.out.println("谢谢您的使用!");
- System.exit(0);
- break;
- default: // 一级菜单输入错误,需要重新选择
- System.out.print("\n输入有误!请重新选择,输入数字: ");
- break;
- }
- } while (flag);
- }
- }
3.2 Data类
- package cn.itcast;
- /**
- * 存放购物系统的初始化数据的数据类,该类只是存放了已有的商品信息和顾客信息
- *
- * @author
- *
- */
- public class Data {
- /**
- * 默认构造方法,初始化变量,由于都是数组对象或类对象,所以都需要采用new
- *
- */
- public Data() {
- goodsName = new String[50] ;
- goodsPrice = new double[50] ;
- custNo = new int[100] ;
- custBirth = new String[100];
- custScore = new int[100] ;
- manager = new Manager() ;
- }
- /**
- * 初始化该类的数据
- *
- */
- public void initial() {
- /*====================添加了初始的7种商品信息====================*/
- goodsName [0] = "addidas运动鞋";
- goodsPrice[0] = 880D;
- goodsName [1] = "Kappa网球裙";
- goodsPrice[1] = 200D;
- goodsName [2] = "网球拍";
- goodsPrice[2] = 780D;
- goodsName [3] = "addidasT恤";
- goodsPrice[3] = 420.77999999999997D;
- goodsName [4] = "Nike运动鞋";
- goodsPrice[4] = 900D;
- goodsName [5] = "Kappa网球";
- goodsPrice[5] = 45D;
- goodsName [6] = "KappaT恤";
- goodsPrice[6] = 245D;
- /*====================添加了初始的7个顾客信息====================*/
- custNo [0] = 1900;
- custBirth[0] = "08/05";
- custScore[0] = 2000;
- custNo [1] = 1711;
- custBirth[1] = "07/13";
- custScore[1] = 4000;
- custNo [2] = 1623;
- custBirth[2] = "06/26";
- custScore[2] = 5000;
- custNo [3] = 1545;
- custBirth[3] = "04/08";
- custScore[3] = 2200;
- custNo [4] = 1464;
- custBirth[4] = "08/16";
- custScore[4] = 1000;
- custNo [5] = 1372;
- custBirth[5] = "12/23";
- custScore[5] = 3000;
- custNo [6] = 1286;
- custBirth[6] = "12/21";
- custScore[6] = 10080;
- }
- /*====================定义该类所拥有的变量====================*/
- public String goodsName []; // 商品的名称
- public double goodsPrice[]; // 商品的价格
- public int custNo []; // 顾客的会员号
- public String custBirth []; // 顾客的生日
- public int custScore []; // 顾客的积分
- public Manager manager ; // 管理员类,仅仅存储了管理员的用户名和密码
- }
3.3 Manager类
- package cn.itcast;
- /**
- * 管理员类,仅仅存储了管理员的用户名和密码
- *
- * @author
- *
- */
- public class Manager {
- /**
- * 设置默认的用户名和密码
- *
- */
- public Manager() {
- username = "itcast";
- password = "itcast";
- }
- /*====================定义该类所拥有的变量====================*/
- public String username; // 用户名
- public String password; // 密码
- }
3.4 VerifyEqual类
- package cn.itcast;
- import java.util.Scanner;
- /**
- * 验证用户登录的账户和密码是否正确的类
- *
- * @author
- *
- */
- public class VerifyEqual {
- /**
- * 空构造方法
- *
- */
- public VerifyEqual() {
- }
- /**
- * 执行验证的方法
- *
- * @param s 用于验证的正确的用户名
- * @param s1 用于验证的正确的密码
- * @return
- */
- public boolean verify(String s, String s1) {
- // 由用户输入用户名
- System.out.print("请输入用户名:");
- Scanner scanner = new Scanner(System.in);
- String s2 = scanner.next();
- // 由用户输入密码
- System.out.print("请输入密码:");
- scanner = new Scanner(System.in);
- String s3 = scanner.next();
- // 判断用户输入的信息是否和已有的信息一致
- return s2.equals(s) && s1.equals(s3);
- }
- }
3.5 Menu类
- package cn.itcast;
- import java.util.Scanner;
- /**
- * 菜单类,用于显示所有级菜单供用户选择
- *
- * @author
- *
- */
- public class Menu {
- /**
- * 空构造方法
- *
- */
- public Menu() {
- }
- /**
- * 设置菜单类中的数据信息
- *
- * @param as
- * @param ad
- * @param ai
- * @param as1
- * @param ai1
- */
- public void setData(String as[], double ad[], int ai[], String as1[], int ai1[]) {
- goodsName = as;
- goodsPrice = ad;
- custNo = ai;
- custBirth = as1;
- custScore = ai1;
- }
- /**
- * 显示一级菜单,即登录界面
- *
- */
- public void showLoginMenu() {
- System.out.println("\n\n\t\t\t 欢迎使用itcast购物管理系统1.0版\n\n");
- System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
- System.out.println("\t\t\t\t 1. 登 录 系 统\n\n");
- System.out.println("\t\t\t\t 2. 更 改 管 理 员 信 息\n\n");
- System.out.println("\t\t\t\t 3. 退 出\n\n");
- System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
- System.out.print("请选择,输入数字:");
- }
- /**
- * 显示二级菜单,即系统的主菜单,这个方法里面包含了对这个菜单处理的所有流程
- *
- */
- public void showMainMenu() {
- // 显示二级菜单,即系统的主菜单
- System.out.println("\n\n\t\t\t\t欢迎使用购物管理系统\n");
- System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
- System.out.println("\t\t\t\t 1. 客 户 信 息 管 理\n");
- System.out.println("\t\t\t\t 2. 购 物 结 算\n");
- System.out.println("\t\t\t\t 3. 真 情 回 馈\n");
- System.out.println("\t\t\t\t 4. 注 销\n");
- System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
- // 用户选择服务项目
- System.out.print("请选择,输入数字:");
- Scanner scanner = new Scanner(System.in);
- // 设置标志用于控制循环
- boolean flag = false;
- do {
- String s = scanner.next();
- // 用户选择"客户信息管理"
- if (s.equals("1")) {
- // 显示客户信息管理菜单并处理这个菜单的整个流程,当这个流程处理完
- showCustMMenu();
- break;
- }
- // 用户选择"购物结算"
- if (s.equals("2")) {
- // 定义购物结算类的对象,并处理整个购物结算的流程
- Pay pay = new Pay();
- pay.setData(goodsName, goodsPrice, custNo, custBirth, custScore);
- pay.calcPrice();
- break;
- }
- // 用户选择"真情回馈"
- if (s.equals("3")) {
- // 处理真情回馈的整个处理流程
- showSendGMenu();
- break;
- }
- // 用户选择"注销"
- if (s.equals("4")) {
- // 显示一级菜单,此时会返回至StartSMS类中的一级菜单处理流程
- showLoginMenu();
- break;
- }
- System.out.print("输入错误,请重新输入数字:");
- flag = false;
- } while (!flag);
- }
- /**
- * 显示三级菜单-客户信息管理,并处理所有客户信息管理的流程
- *
- */
- public void showCustMMenu() {
- System.out.println("购物管理系统 > 客户信息管理\n");
- System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
- System.out.println("\t\t\t\t 1. 显 示 所 有 客 户 信 息\n");
- System.out.println("\t\t\t\t 2. 添 加 客 户 信 息\n");
- System.out.println("\t\t\t\t 3. 修 改 客 户 信 息\n");
- System.out.println("\t\t\t\t 4. 查 询 客 户 信 息\n");
- System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
- System.out.print("请选择,输入数字或按'n'返回上一级菜单:");
- Scanner scanner = new Scanner(System.in);
- boolean flag = true;
- do {
- // 创建客户信息管理对象,并设置数据,这里的数据还是原始的那些数据
- CustManagement custmanagement = new CustManagement();
- custmanagement.setData(goodsName, goodsPrice, custNo, custBirth, custScore);
- String s = scanner.next();
- // 客户选择"显示所有客户信息"
- if (s.equals("1")) {
- custmanagement.show();
- break;
- }
- // 客户选择"添加客户信息"
- if (s.equals("2")) {
- custmanagement.add();
- break;
- }
- // 客户选择"修改客户信息"
- if (s.equals("3")) {
- custmanagement.modify();
- break;
- }
- // 客户选择"查询客户信息"
- if (s.equals("4")) {
- custmanagement.search();
- break;
- }
- // 客户选择"返回上一级菜单"
- if (s.equals("n")) {
- showMainMenu();
- break;
- }
- System.out.println("输入错误, 请重新输入数字:");
- flag = false;
- } while (!flag);
- }
- /**
- * 显示三级菜单-真情回馈,并处理所有真情回馈的流程
- *
- */
- public void showSendGMenu() {
- System.out.println("购物管理系统 > 真情回馈\n");
- System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
- System.out.println("\t\t\t\t 1. 幸 运 大 放 送\n");
- System.out.println("\t\t\t\t 2. 幸 运 抽 奖\n");
- System.out.println("\t\t\t\t 3. 生 日 问 候\n");
- System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
- System.out.print("请选择,输入数字或按'n'返回上一级菜单:");
- Scanner scanner = new Scanner(System.in);
- // 创建礼物管理对象,并设置数据,这里的数据还是原始的那些数据
- GiftManagement giftmanagement = new GiftManagement();
- giftmanagement.setData(goodsName, goodsPrice, custNo, custBirth, custScore);
- boolean flag = true;
- do {
- String s = scanner.next();
- // 客户选择"幸运大放送"
- if (s.equals("1")) {
- giftmanagement.sendGoldenCust();
- break;
- }
- // 客户选择"幸运抽奖"
- if (s.equals("2")) {
- giftmanagement.sendLuckyCust();
- break;
- }
- // 客户选择"生日问候"
- if (s.equals("3")) {
- giftmanagement.sendBirthCust();
- break;
- }
- // 客户选择"返回上一级菜单"
- if (s.equals("n")) {
- showMainMenu();
- break;
- }
- System.out.println("输入错误, 请重新输入数字:");
- flag = false;
- } while (!flag);
- }
- /*====================定义该类所拥有的变量====================*/
- public String goodsName []; // 商品的名称
- public double goodsPrice[]; // 商品的价格
- public int custNo []; // 顾客的会员号
- public String custBirth []; // 顾客的生日
- public int custScore []; // 顾客的积分
- }
3.6 CustManagement类
- package cn.itcast;
- import java.util.Scanner;
- /**
- * 顾客信息管理类
- *
- * @author
- *
- */
- public class CustManagement {
- /**
- * 空构造方法
- *
- */
- public CustManagement() {
- }
- /**
- * 设置顾客信息管理类的数据信息
- *
- * @param as
- * @param ad
- * @param ai
- * @param as1
- * @param ai1
- */
- public void setData(String as[], double ad[], int ai[], String as1[], int ai1[]) {
- goodsName = as;
- goodsPrice = ad;
- custNo = ai;
- custBirth = as1;
- custScore = ai1;
- }
- /**
- * 返回上一级菜单,即二级菜单-客户信息管理菜单
- *
- */
- public void returnLastMenu() {
- System.out.print("\n\n请按'n'返回上一级菜单:");
- Scanner scanner = new Scanner(System.in);
- boolean flag = true;
- do
- if (scanner.next().equals("n")) {
- // 返回上一级菜单,这里新建了一个菜单对象,只是在用户看来其实还是同样的处理流程,
- // 不过对于程序来说却又开始了一个新的二级菜单处理流程
- Menu menu = new Menu();
- menu.setData(goodsName, goodsPrice, custNo, custBirth, custScore);
- menu.showCustMMenu();
- } else {
- System.out.print("输入错误, 请重新'n'返回上一级菜单:");
- flag = false;
- }
- while (!flag);
- }
- /**
- * 添加客户信息
- *
- */
- public void add() {
- System.out.println("购物管理系统 > 客户信息管理 > 添加客户信息\n\n");
- Scanner scanner = new Scanner(System.in);
- System.out.print("请输入会员号(<4位整数>):");
- int i = scanner.nextInt();
- System.out.print("请输入会员生日(月/日<用两位数表示>):");
- String s = scanner.next();
- System.out.print("请输入积分:");
- int j = scanner.nextInt();
- int k = -1;
- int l = 0;
- do {
- if (l >= custNo.length)
- break;
- // 寻找数组中的第一个空位置,用来存储新的顾客信息
- if (custNo[l] == 0) {
- k = l;
- break;
- }
- l++;
- } while (true);
- custNo [k] = i;
- custBirth[k] = s;
- custScore[k] = j;
- System.out.println("新会员添加成功!");
- // 返回上一级菜单
- returnLastMenu();
- }
- /**
- * 修改客户信息
- *
- */
- public void modify() {
- System.out.println("购物管理系统 > 客户信息管理 > 修改客户信息\n\n");
- System.out.print("请输入会员号:");
- Scanner scanner = new Scanner(System.in);
- int i = scanner.nextInt();
- System.out.println(" 会员号 生日 积分 ");
- System.out.println("------------|------------|---------------");
- int j = -1;
- int k = 0;
- do {
- if (k >= custNo.length)
- break;
- // 显示该会员的信息
- if (custNo[k] == i) {
- System.out.println((new StringBuilder()).append(custNo[k])
- .append("\t\t").append(custBirth[k]).append("\t\t")
- .append(custScore[k]).toString());
- j = k;
- break;
- }
- k++;
- } while (true);
- // 该会员存在,则进行修改信息流程
- if (j != -1) {
- System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
- System.out.println("\t\t\t\t1.修 改 会 员 生 日.\n");
- System.out.println("\t\t\t\t2.修 改 会 员 积 分.\n");
- System.out.println("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
- System.out.print("请选择,输入数字:");
- switch (scanner.nextInt()) {
- case 1: // "修改会员生日"
- System.out.print("请输入修改后的生日:");
- custBirth[j] = scanner.next();
- System.out.println("生日信息已更改!");
- break;
- case 2: // "修改会员积分"
- System.out.print("请输入修改后的会员积分:");
- custScore[j] = scanner.nextInt();
- System.out.println("会员积分已更改!");
- break;
- }
- } else {
- System.out.println("抱歉,没有你查询的会员。");
- }
- // 返回上一级菜单
- returnLastMenu();
- }
- /**
- * 查询客户信息
- *
- */
- public void search() {
- System.out.println("购物管理系统 > 客户信息管理 > 查询客户信息\n");
- Scanner scanner = new Scanner(System.in);
- for (String s = "y"; s.equals("y"); s = scanner.next()) {
- System.out.print("请输入会员号:");
- int i = scanner.nextInt();
- System.out.println(" 会员号 生日 积分 ");
- System.out.println("------------|------------|---------------");
- boolean flag = false;
- int j = 0;
- do {
- if (j >= custNo.length)
- break;
- // 显示该会员的信息
- if (custNo[j] == i) {
- System.out.println((new StringBuilder()).append(custNo[j])
- .append("\t\t").append(custBirth[j]).append("\t\t")
- .append(custScore[j]).toString());
- flag = true;
- break;
- }
- j++;
- } while (true);
- if (!flag)
- System.out.println("抱歉,没有你查询的会员信息。");
- System.out.print("\n要继续查询吗(y/n):");
- }
- // 返回上一级菜单
- returnLastMenu();
- }
- /**
- * 显示所有客户信息
- *
- */
- public void show() {
- System.out.println("购物管理系统 > 客户信息管理 > 显示客户信息\n\n");
- System.out.println(" 会员号 生日 积分 ");
- System.out.println("------------|------------|---------------");
- int i = custNo.length;
- for (int j = 0; j < i && custNo[j] != 0; j++)
- System.out.println((new StringBuilder()).append(custNo[j]).append(
- "\t\t").append(custBirth[j]).append("\t\t").append(
- custScore[j]).toString());
- // 返回上一级菜单
- returnLastMenu();
- }
- /*====================定义该类所拥有的变量====================*/
- public String goodsName []; // 商品的名称
- public double goodsPrice[]; // 商品的价格
- public int custNo []; // 顾客的会员号
- public String custBirth []; // 顾客的生日
- public int custScore []; // 顾客的积分
- }
3.7 Pay类
- package cn.itcast;
- import java.util.Scanner;
- /**
- * 处理顾客购买商品以及结算的类
- *
- * @author
- *
- */
- public class Pay {
- /**
- * 空构造方法
- *
- */
- public Pay() {
- }
- /**
- * 设置购物结算类的数据信息
- *
- * @param as
- * @param ad
- * @param ai
- * @param as1
- * @param ai1
- */
- public void setData(String as[], double ad[], int ai[], String as1[], int ai1[]) {
- goodsName = as;
- goodsPrice = ad;
- custNo = ai;
- custBirth = as1;
- custScore = ai1;
- }
- /**
- * 根据会员信息确定折扣率
- *
- * @param i
- * @param ai
- * @param ai1
- * @return
- */
- public double getDiscount(int i, int ai[], int ai1[]) {
- int j = -1;
- int k = 0;
- do {
- if (k >= ai.length)
- break;
- if (i == ai[k]) {
- j = k;
- break;
- }
- k++;
- } while (true);
- double d;
- if (ai1[j] < 1000)
- d = 0.94999999999999996D;
- else if (1000 <= ai1[j] && ai1[j] < 2000)
- d = 0.90000000000000002D;
- else if (2000 <= ai1[j] && ai1[j] < 3000)
- d = 0.84999999999999998D;
- else if (3000 <= ai1[j] && ai1[j] < 4000)
- d = 0.80000000000000004D;
- else if (4000 <= ai1[j] && ai1[j] < 6000)
- d = 0.75D;
- else if (6000 <= ai1[j] && ai1[j] < 8000)
- d = 0.69999999999999996D;
- else
- d = 0.59999999999999998D;
- return d;
- }
- /**
- * 该类的关键方法,用于处理购物和结算
- *
- */
- public void calcPrice() {
- String s2 = "";
- double d1 = 0.0D;
- double d2 = 0.0D;
- int l = 0;
- double d4 = 0;
- System.out.println("购物管理系统 > 购物结算\n\n");
- System.out.println("*************************************");
- System.out.println("请选择购买的商品编号:");
- // 显示所有的可购买商品信息,这里的信息就是最初的那些初始化商品数据
- for (l = 0; l < goodsName.length && goodsName[l] != null; l++) {
- d4++;
- System.out.println((new StringBuilder()).append(d4).append(": ")
- .append(goodsName[l]).append("\t").toString());
- }
- System.out.println("*************************************\n");
- Scanner scanner = new Scanner(System.in);
- System.out.print("\t请输入会员号:");
- int i = scanner.nextInt();
- // 根据会员信息获取打折信息
- d4 = getDiscount(i, custNo, custScore);
- String s1;
- do {
- System.out.print("\t请输入商品编号:");
- int j = scanner.nextInt();
- System.out.print("\t请输入数目:");
- int k = scanner.nextInt();
- double d = goodsPrice[j - 1];
- String s = goodsName[j - 1];
- d1 += d * (double) k;
- s2 = (new StringBuilder()).append(s2).append("\n").append(s)
- .append("\t").append("¥").append(d).append("\t\t")
- .append(k).append("\t\t").append("¥")
- .append(d * (double) k).append("\t").toString();
- System.out.print("\t是否继续(y/n)");
- s1 = scanner.next();
- } while (s1.equals("y"));
- d2 = d1 * d4; // 打折后的总价
- System.out.println("\n");
- System.out.println("*****************消费清单*********************");
- System.out.println("物品\t\t单价\t\t个数\t\t金额\t");
- System.out.print(s2);
- System.out.println((new StringBuilder()).append("\n折扣:\t").append(d4).toString());
- System.out.println((new StringBuilder()).append("金额总计:\t¥").append(d2).toString());
- System.out.print("实际交费:\t¥");
- double d3 = scanner.nextDouble();
- System.out.println((new StringBuilder()).append("找钱:\t¥").append(d3 - d2).toString());
- int i1 = ((int) d2 / 100) * 3;
- int j1 = 0;
- do {
- if (j1 >= custNo.length)
- break;
- if (custNo[j1] == i) {
- custScore[j1] = custScore[j1] + i1;
- System.out.println((new StringBuilder()).append("本次购物所获的积分是: ")
- .append(i1).toString());
- break;
- }
- j1++;
- } while (true);
- System.out.print("\n请'n'返回上一级菜单:");
- if (scanner.next().equals("n")) {
- // 返回上一级菜单,这里新建了一个菜单对象,只是在用户看来其实还是同样的处理流程,
- // 不过对于程序来说却又开始了一个新的二级菜单处理流程
- Menu menu = new Menu();
- menu.setData(goodsName, goodsPrice, custNo, custBirth, custScore);
- menu.showMainMenu();
- }
- }
- /*====================定义该类所拥有的变量====================*/
- public String goodsName []; // 商品的名称
- public double goodsPrice[]; // 商品的价格
- public int custNo []; // 顾客的会员号
- public String custBirth []; // 顾客的生日
- public int custScore []; // 顾客的积分
- }
3.8 GiftManagement类
- package cn.itcast;
- import java.util.Scanner;
- /**
- * 礼物管理类
- *
- * @author
- *
- */
- public class GiftManagement {
- /**
- * 空构造方法
- *
- */
- public GiftManagement() {
- }
- /**
- * 设置礼物管理类的数据信息
- *
- * @param as
- * @param ad
- * @param ai
- * @param as1
- * @param ai1
- */
- public void setData(String as[], double ad[], int ai[], String as1[], int ai1[]) {
- goodsName = as;
- goodsPrice = ad;
- custNo = ai;
- custBirth = as1;
- custScore = ai1;
- }
- /**
- * 返回上一级菜单,即二级菜单-真情回馈菜单
- *
- */
- public void returnLastMenu() {
- System.out.print("\n\n请按'n'返回上一级菜单:");
- Scanner scanner = new Scanner(System.in);
- boolean flag = true;
- do
- if (scanner.next().equals("n")) {
- // 返回上一级菜单,这里新建了一个菜单对象,只是在用户看来其实还是同样的处理流程,
- // 不过对于程序来说却又开始了一个新的二级菜单处理流程
- Menu menu = new Menu();
- menu.setData(goodsName, goodsPrice, custNo, custBirth, custScore);
- menu.showCustMMenu();
- } else {
- System.out.print("输入错误, 请重新'n'返回上一级菜单:");
- flag = false;
- }
- while (!flag);
- }
- /**
- * 生日问候
- *
- */
- public void sendBirthCust() {
- System.out.println("购物管理系统 > 生日问候\n\n");
- System.out.print("请输入今天的日期(月/日<用两位表示>):");
- Scanner scanner = new Scanner(System.in);
- String s = scanner.next();
- System.out.println(s);
- String s1 = "";
- boolean flag = false;
- for (int i = 0; i < custBirth.length; i++)
- if (custBirth[i] != null && custBirth[i].equals(s)) {
- s1 = (new StringBuilder()).append(s1).append(custNo[i]).append(
- "\n").toString();
- flag = true;
- }
- // 这里的礼物是固定的,所以没有用礼物类
- if (flag) {
- System.out.println("过生日的会员是:");
- System.out.println(s1);
- System.out.println("恭喜!获赠MP3一个!");
- } else {
- System.out.println("今天没有过生日的会员!");
- }
- // 返回上一级菜单
- returnLastMenu();
- }
- /**
- * 幸运抽奖,注意这里是随机的抽奖,所以需要随机数,只需要自己制定一个抽奖规则就可以
- *
- */
- public void sendLuckyCust() {
- System.out.println("购物管理系统 > 幸运抽奖\n\n");
- System.out.print("是否开始(y/n):");
- Scanner scanner = new Scanner(System.in);
- if (scanner.next().equals("y")) {
- int i = (int) (Math.random() * 10D); // 产生一个随机数
- String s = "";
- boolean flag = false;
- for (int k = 0; k < custNo.length && custNo[k] != 0; k++) {
- // 拿随机数与顾客会员号的相应结果进行比较,从而判断是否有顾客中奖
- int j = (custNo[k] / 100) % 10;
- if (j == i) {
- s = (new StringBuilder()).append(s).append(custNo[k])
- .append("\t").toString();
- flag = true;
- }
- }
- // 固定的奖品,所以不需要礼物类
- if (flag)
- System.out.println((new StringBuilder()).append("幸运客户获赠MP3:")
- .append(s).toString());
- else
- System.out.println("无幸运客户。");
- }
- // 返回上一级菜单
- returnLastMenu();
- }
- /**
- * 幸运大放送,取积分最高的会员作为幸运者,送其奖品
- *
- */
- public void sendGoldenCust() {
- System.out.println("购物管理系统 > 幸运大放送\n\n");
- int i = 0;
- int j = custScore[0];
- for (int k = 0; k < custScore.length && custScore[k] != 0; k++) {
- // 找到积分最高的会员
- if (custScore[k] > j) {
- j = custScore[k];
- i = k;
- }
- }
- System.out.println((new StringBuilder()).append("具有最高积分的会员是: ").append(
- custNo[i]).append("\t").append(custBirth[i]).append("\t")
- .append(custScore[i]).toString());
- // 创建礼物类,并对礼物信息进行设置,这里的礼物是固定的信息
- Gift gift = new Gift();
- gift.name = "苹果笔记本电脑";
- gift.price = 12000D;
- System.out.print("恭喜!获赠礼品: ");
- System.out.println(gift);
- // 返回上一级菜单
- returnLastMenu();
- }
- /*====================定义该类所拥有的变量====================*/
- public String goodsName []; // 商品的名称
- public double goodsPrice[]; // 商品的价格
- public int custNo []; // 顾客的会员号
- public String custBirth []; // 顾客的生日
- public int custScore []; // 顾客的积分
- }
3.9 Gift类
- package cn.itcast;
- /**
- * 用来存放真情回馈中的礼物的类
- */
- public class Gift {
- /**
- * 空构造方法
- *
- */
- public Gift() {
- }
- /**
- * 根据礼物对象的变量返回礼物的全部信息
- *
- */
- public String toString() {
- return (new StringBuilder()).append("一个价值¥").append(price)
- .append("的").append(name).toString();
- }
- /*====================定义该类所拥有的变量====================*/
- public String name ; // 礼物名字
- public double price; // 礼物价格
- }
3.10 代码总结
从上面的9个类的代码来看,有一些需要注意的地方:
(1)在许多类中都定义了与Data中基本一样的成员变量,只是没有Manager对象而已,这是为了让数据一层层保存和传递,通过setData()方法实现,不过这种方法其实并不是很好,并且一般来说成员变量应该最好设置为私有的,这里这样的设计是为了操作方便,使系统更简单一些,安全性不好。
(2)注意到所有要进行字符串拼接的地方都使用JAVA中的StringBuilder类,这是为了高效处理字符串拼接,防止String类带来的拼接数据冗余。
(3)这些设计中的流程并不是非常合理,大家可以自己的需要进行修改。
(4)代码中基本上没有考虑异常时的处理,所以当输入时出现错误的时候,普通错误可以进行重新输入,但是如果出现不匹配等错误,直接会出现异常,从而退出系统,这些也是本设计的缺陷,可以通过正则表达式等来完善一些。
总之,给出的代码仅供参考,大家可以根据需要进行修改,这些代码都是经过验证的,可以直接运行。
4. 总结
这个设计只是为了说明一些基本的设计思想和设计理念,以及设计过程中需要考虑的问题,主要还是为了说明怎样用面向对象的思想去解决现实生活中的问题,所以设计相对简单,不过希望大家可以通过这个设计理解这些基本的思想,从而帮助大家理想面向对象的基本思想。
总之,语言只是一种解决问题的工具,大家可以用C++、C#等其他语言来实现这一系统,只要有良好的设计理念和设计思想就可以。再次强调,本设计仅供参考,欢迎大家参与讨论,有错误的地方欢迎大家指正,谢谢。