问题描述
参考肯德基官网的信息模拟肯德基快餐店的收银系统,结合设计模式(2种以上)至少实现系统的以下功能:
1.正常餐品结算和找零。
2.基本套餐结算和找零。
3.使用优惠劵购买餐品结算和找零。
4.可在一定时间段参与店内活动(自行设计或参考官网信息)。
5.模拟打印小票的功能(写到文件中)。
问题分析
要产生不同的食物类,不难想到要用到抽象工厂模式,即定义抽象工厂类,具体工厂类生产对应的具体产品。
要根据不同的结账方式实现餐品结算,就可以用到策略模式,即用每一个结账类封装不同的结账方式。
UML类图
工厂模式
策略模式
方法说明
本系统的层级结构如下:
本系统的菜单层级关系如下:
以下就每个方法进行具体说明。
(食物基本信息类baseFood)
因为要在主菜单打印食物信息,所以需要一个食物信息类和打印食物信息的基类。
public class baseFood {
// 类别
protected String kind;
// 数量
protected int num;
// 价格
protected float price;
// 合计
public float totalPrice()
{
return this.num * this.price;
}
}
(打印食物信息接口)
public interface IFood {
String printMessage();
}
(抽象肯德基工厂接口类)
抽象工厂类,定义了如下抽象方法。
createHamburg()制作汉堡包;
createIceCream()制作冰激凌;
createBeverage()制作饮料;
createChicken()制作炸鸡;
其中的参数kind传入食品的代号,num传入食品的数量。
public interface KFCFactoryImpl {
public Hamburg createHamburg(int kind,int num);
public IceCream createIceCream(int kind, int num);
public Beverage createBeverage(int kind, int num);
public Chicken createChicken(int kind, int num);
}
(具体肯德基厨房类)
具体肯德基厨房实现抽象接口生产所需的食物。本程序实现了四个抽象产品:
汉堡包Hamburg
冰激凌IceCream
饮料Beverage
炸鸡 Chicken
//具体肯德基厨房工厂
public class KFCFoodFactory implements KFCFactoryImpl {
@Override
//制作汉堡包
public Hamburg createHamburg(int kind, int num) {
if(1 == kind){
return new BigMacHam(num);//巨无霸
}else if(2 == kind){
return new SpicyChickenHam(num);//香辣鸡腿堡
}else if(3 == kind){
return new OrleansChickenHam(num);//奥尔良鸡腿堡
}else{
return null;
}
}
//制作冰激凌
@Override
public IceCream createIceCream(int kind, int num) {
if(1 == kind){
return new strawberrySundae(num);//草莓圣代
}else if(2 == kind){
return new blueberrySundae(num);//蓝莓圣代
}else if(3 == kind){
return new iceCreamCone(num);//原味甜筒
}else{
return null;
}
}
//制作饮料
@Override
public Beverage createBeverage(int kind, int num) {
if(1 == kind){
return new CocaCola(num);//可口可乐
}else if(2 == kind){
return new juice(num);//九珍果汁
}else{
return null;
}
}
//制作炸鸡
@Override
public Chicken createChicken(int kind, int num) {
if(1 == kind){
return new chickenNugget(num);//上校鸡块
}else if(2 == kind){
return new chickenRolls(num);//鸡肉卷
}else if(3 == kind){
return new popcornChicken(num);//鸡米花
}else{
return null;
}
}
}
(汉堡包基类Hamburg)
这里既用到了extends继承食物信息基类又用到了implements实现打印食物接口。
abstract class Hamburg extends baseFood implements IFood{
@Override
public String printMessage() {
return (this.kind+"\t"+this.price+"\t"+this.num+"\t"+this.totalPrice());
}
}
(汉堡包派生类BigMacHam)
public class BigMacHam extends Hamburg{
public BigMacHam(int num) {
this.kind = "巨无霸大汉堡";
this.num = num;
this.price = 25.0f;
}
}
对于新奥尔良堡、香辣鸡腿堡的具体汉堡包食物类与这里列出的巨无霸汉堡大同小异,只需要修改this.kind。其余的冰激凌类、炸鸡类、饮料类和其派生类的关系与汉堡包类与其派生类的关系同理,在此不做赘述。
(顾客类)
这里顾客类的成员函数ShowBill实现打印小票文件,OutBill显示订单,这里利用集合动态数组添加订单信息。
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
public class Customer {
private KFCFactoryImpl kfcFactory;
public Customer(KFCFactoryImpl kfcFactory) {
this.kfcFactory = kfcFactory;
}
private ArrayList<String> billList = new ArrayList<>();
//打印小票文件
public void showBill() throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("D://text.txt", true));
bw.write("*****************************************************\r\n");
bw.write(" **欢迎光临荔枝堡** \r\n");
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
bw.write("订餐时间:"+df.format(new Date())+"\r\n");// new Date()为获取当前系统时间
bw.write("名称 \t\t单价\t数量\t价格\r\n");
for(String str:billList){
bw.write(str);
bw.newLine();
bw.flush();
}
}
//显示订单
public void outBill(){
for(String str:billList){
System.out.println(str);
}
}
//获得汉堡
public float getHamburg(int choose,int num){
Hamburg hamburg;
hamburg = kfcFactory.createHamburg(choose,num);
System.out.print(hamburg.printMessage());
billList.add(hamburg.printMessage());
return hamburg.totalPrice();
}
//获得冰淇淋
public float getIceCream(int choose,int num){
IceCream icecream;
icecream = kfcFactory.createIceCream(choose,num);
System.out.print(icecream.printMessage());
billList.add(icecream.printMessage());
return icecream.totalPrice();
}
//获得饮料
public float getBeverage(int choose,int num){
Beverage beverage;
beverage = kfcFactory.createBeverage(choose,num);
System.out.print(beverage.printMessage());
billList.add(beverage.printMessage());
return beverage.totalPrice();
}
//获得炸鸡
public float getChicken(int choose,int num){
Chicken chicken;
chicken = kfcFactory.createChicken(choose,num);
System.out.print(chicken.printMessage());
billList.add(chicken.printMessage());
return chicken.totalPrice();
}
//获得套餐
public float getSetMeal(int choose,int num){
Hamburg hamburg;
Chicken chicken;
IceCream iceCream;
Beverage beverage;
float money;
if(1 == choose){
hamburg = kfcFactory.createHamburg(3,1);
beverage = kfcFactory.createBeverage(2,1);
chicken = kfcFactory.createChicken(1,1);
billList.add(hamburg.printMessage());
billList.add(beverage.printMessage());
billList.add(chicken.printMessage());
money = Math.round(0.9*(hamburg.totalPrice()+beverage.totalPrice()+chicken.totalPrice())*num);
return money;
}else if(2 == choose){
hamburg = kfcFactory.createHamburg(2,3);
beverage = kfcFactory.createBeverage(2,3);
chicken = kfcFactory.createChicken(2,2);
iceCream = kfcFactory.createIceCream(1,1);
billList.add(hamburg.printMessage());
billList.add(beverage.printMessage());
billList.add(chicken.printMessage());
billList.add(iceCream.printMessage());
money = Math.round(0.9*(hamburg.totalPrice()+beverage.totalPrice()+chicken.totalPrice()+iceCream.totalPrice())*num);
return money;
}else if(3 == choose){
hamburg = kfcFactory.createHamburg(1,2);
iceCream = kfcFactory.createIceCream(3,2);
beverage = kfcFactory.createBeverage(2,2);
chicken = kfcFactory.createChicken(1,1);
billList.add(hamburg.printMessage());
billList.add(beverage.printMessage());
billList.add(chicken.printMessage());
billList.add(iceCream.printMessage());
money = Math.round(0.9*(hamburg.totalPrice()+beverage.totalPrice()+chicken.totalPrice()+iceCream.totalPrice())*num);
return money;
}else{
System.out.println("没有该套餐!!!");
return 0;
}
}
}
(菜单类Menu)
由菜单类实现主界面的选择显示界面。
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
/**
* @Author:Star
* @Date:Created in 18:54 2019/5/11
* @Description:
*/
class Menu {
Scanner input = new Scanner(System.in);
private KFCFactoryImpl kfcFactory;
private Customer customer;
private float hamburgMoney;
private float iceCreamMoney;
private float beverageMoney;
private float chickenFiresMoney;
private float setMealMoney;
private float sumMoney;
public Menu(KFCFactoryImpl kfcFactory, Customer customer) {
this.kfcFactory = kfcFactory;
this.customer = customer;
}
//欢迎界面
public void menu() throws IOException {
System.out.println("******欢迎光临荔枝堡***");
System.out.println(" *** *** ");
System.out.println(" ******** ******** ");
System.out.println("*** * ***");
System.out.println(" *** 1.开始点餐 *** ");
System.out.println(" ** 2.退出系统 ** ");
System.out.println(" ** ** ");
System.out.println(" ** **" );
System.out.println(" ** ");
System.out.print("请选择>");
int choose = input.nextInt();
switch (choose){
case 1:
productionMenu();
int pay = payMoney(customer,getMoney());
printBill(customer,getMoney(),pay);
break;
case 2:
System.out.println("您已成功退出点餐系统...");
default:
System.out.println("选择错误....");
}
}
//食物产品界面
public void productionMenu() throws IOException {
boolean flag = true;
while(flag == true){
System.out.println("当前商品如下:");
System.out.println("==================");
System.out.println("1.汉堡");
System.out.println("==================");
System.out.println("2.冰淇淋");
System.out.println("==================");
System.out.println("3.饮料");
System.out.println("==================");
System.out.println("4.烤鸡");
System.out.println("==================");
System.out.println("5.套餐");
System.out.println("==================");
System.out.println("6.结束订餐,查看订单");
System.out.println("==================");
System.out.print("请选择>");
int choose = input.nextInt();
switch (choose){
case 1:
hamburgMenu();
break;
case 2:
iceCreamMenu();
break;
case 3:
beverageMenu();
break;
case 4:
chickenFiresMenu();
break;
case 5:
setMeal();
break;
case 6:
float money = getMoney();
showBills(customer,money);
break;
default:
System.out.println("选择错误...");
}
if(choose == 6){
flag = false;
}
}
}
//汉堡菜单界面
public void hamburgMenu(){
System.out.println("1.巨无霸-----------25元");
System.out.println("2.香辣鸡腿堡--------18元");
System.out.println("3.奥尔良鸡腿堡------18元");
System.out.print("请选择>");
int choose = input.nextInt();
System.out.print("请输入数量>");
int num = input.nextInt();
hamburgMoney = customer.getHamburg(choose,num);
}
//冰淇淋菜单界面
public void iceCreamMenu(){
System.out.println("1.草莓圣代------12元");
System.out.println("2.蓝莓圣代------12元");
System.out.println("3. 甜筒--------6元");
System.out.print("请选择>");
int choose = input.nextInt();
System.out.print("请输入数量>");
int num = input.nextInt();
iceCreamMoney = customer.getIceCream(choose,num);
}
//饮料菜单界面
public void beverageMenu(){
System.out.println("1.可口可乐------12元");
System.out.println("2.九珍果汁------11元");
System.out.print("请选择>");
int choose = input.nextInt();
System.out.print("请输入数量>");
int num = input.nextInt();
beverageMoney = customer.getBeverage(choose,num);
}
//炸鸡菜单界面
public void chickenFiresMenu(){
System.out.println("1.上校鸡块------12元");
System.out.println("2. 鸡肉卷 ------10元");
System.out.println("3. 鸡米花 ------8元");
System.out.print("请选择>");
int choose = input.nextInt();
System.out.print("请输入数量>");
int num = input.nextInt();
chickenFiresMoney = customer.getChicken(choose,num);
}
//套餐界面
public void setMeal(){
System.out.println("1.儿童套餐(奥尔良鸡腿堡+九珍果汁+上校鸡块)------35元");
System.out.println("2.家庭套餐(香辣鸡腿堡(3个)+九珍果汁(3杯)+鸡肉卷(2个)+草莓圣代)------118元");
System.out.println("3.情侣套餐(巨无霸(2个)+甜筒(2个)+九珍果汁(2杯)+上校鸡块)------99元");
System.out.print("请选择>");
int choose = input.nextInt();
System.out.print("请输入数量>");
int num = input.nextInt();
setMealMoney = customer.getSetMeal(choose,num);
}
//获得总金额
public float getMoney(){
sumMoney = hamburgMoney+iceCreamMoney+beverageMoney+chickenFiresMoney+setMealMoney;
return sumMoney;
}
//打印账单
public static void printBill(Customer customer, float sumMoney, int pay) throws IOException {
customer.showBill();
BufferedWriter bw=new BufferedWriter(new FileWriter("D://text.txt",true));
bw.write("总计: "+sumMoney);
bw.newLine();
bw.write("付款:"+pay);
bw.newLine();
float y=pay-sumMoney;
bw.write("找零:"+y);
bw.newLine();
bw.write("当前收银员:小荔子\r\n");
bw.write(" 欢迎下次光临!^_^ \r\n");
bw.write("******************************************************\r\n");
bw.flush();
bw.close();
}
//显示订单
public static void showBills(Customer customer,float sumMoney) throws IOException {
customer.outBill();
System.out.println("总计:"+sumMoney);
}
//付款界面
public int payMoney(Customer customer, float sumMoney){
while(true){
System.out.print("请输入付款金额:");
int pay=input.nextInt();
if(pay-sumMoney >= 0){
if(pay >= 100){
System.out.println("您要使用优惠卷结账吗?(y/n)");
System.out.println("优惠卷:满100减20,满200减30!!!");
if(input.next().equals("y")){
if(pay >= 200){
System.out.println("找零:"+(pay-sumMoney+30));
}else {
System.out.println("找零:"+(pay-sumMoney+20));
}
}else{
System.out.println("找零:"+(pay-sumMoney));
}
}else{
System.out.println("找零:"+(pay-sumMoney));
}
}else{
System.out.println("不够哦!!!");
}
return pay;
}
}
}
运行效果
本程序最终的运行效果如下。
开始界面
选餐界面
①单品
②套餐
③查看订单
付款界面
在D盘下生成的小票
总结
模拟肯德基订餐的系统的荔枝堡是运用了工厂方法设计模式设计的一个简单的点餐系统,该系统可以实现正常商品的结算,套餐商品结算,优惠卷的使用以及在文件中记录订餐账单(即模拟订餐小票的打印)。
存在问题:
- 编写过程中,思路不清晰。刚开始在写的时候,想法过于简单,所以在实际编写的过程中,一度发现问题并不断迭代。所以在编写代码之前要理清自己的思路,数据的处理,功能实现的具体方法。
- 设计模式的应用不熟练导致的代码内聚度不够高,耦合不够低。书本上学习的设计模式运用到实际中还是挺困难的,所对于设计模式的学习还是要多与实际问题结合应用。
一定要善于灵活运用设计模式!!!这一次和组员一起做的过程中因为工厂模式没有理解透彻,所以中途写了很多作废掉的代码......(感谢大佬组员带我)
附录:
相关代码已上传至码云仓库https://gitee.com/xinwenruyi/programs-design-method