一、实现功能预览
1.正常餐品结算和找零。
2.基本套餐结算和找零。
3.使用优惠劵购买餐品结算和找零。
4.可在一定时间段参与店内活动。
5.模拟打印小票的功能(写到文件中)。
餐品有:
(1)香辣汉堡 单价:14.0元
(2)奥尔良鸡翅 单价: 2.5元
(3)可乐 单价: 7.0元
(4)番茄薯条 单价: 8.0元
(5)套餐一:香辣汉堡 1 个 + 奥尔良鸡翅 2 个 + 可乐 1 瓶 价格 :20元
(6)套餐二:奥尔良鸡翅 2 个 + 可乐 1 瓶 + 番茄薯条 1 包 价格:15元
下图是菜单界面:
选择1后进入购餐界面:
购完物品后则进行正常的找零与结算并在文件中打印小票;
这里满减与打折叠加,先满减。
打折活动就是实现的在一定的时间范围内实现店内优惠活动,这里用到了Date类与DateFormat类用来获取系统时间,并判断这一天是否是12号,若是则打五折,这个活动一个月就只有一次!
下面是小票的情况:
以上就是简单点餐的功能预览了。
二、实现
虽然是一个简单的点餐系统,但是设计到东西也是有一点难度的,在这里我们需要用到两种设计模式–(1)抽象工厂模式 (2)策略模式
(1)抽象模式可参考我的另一篇博客:https://blog.youkuaiyun.com/qq_42419462/article/details/89796905
(2)策略模式,我还未进行总结(求“月亮”)
为什么用到抽象模式呢?我们需要用到它的优点来进行“预防”!
预防后期的增加产品族,比如我们需要新增加一种口味的汉堡包,这时候我们就会发现我们只需要增加对应口味的汉堡包类,以及增加生产方法就可以了,别的就是在菜单上进行增加了。我们不会涉及到抽象层的修改。这就符合了开闭原则,我们只是扩展的小能手,但我们不修改抽象层!
至于策略模式就是为了能更好的进行选择,菜单那一块就是用到策略模式了。如果后期增加了新口味的汉堡,也能更快的做出修改了。
总之一句话,设计模式的作用就是为了将来能更好的进行维护,方便的我们!
三、代码
读者可以参考代码,更好的学习!如果有问题,欢迎随时评论!
一共有两个包:
package Kfc(第一个)
先写好食物,先写食物的抽象类,面向父类编程:
汉堡包的基类:
package Kfc;
//汉堡的基类
public abstract class Hamburg{
//单价
public float price;
//口味
public String kind;
//数量
public int num;
public float totalPrice(){
return 0;
}
public void printMessage(){
}
}
饮料的基类:
package Kfc;
//饮料基类
public abstract class Beverage {
//单价
public float price;
//口味
public String kind;
//数量
public int num;
public float totalPrice(){
return 0;
}
public void printMessage(){
}
}
鸡翅基类:
package Kfc;
//鸡翅的基类
public abstract class Chickenwarnings{
//单价
public float price;
//口味
public String kind;
//数量
public int num;
public float totalPrice(){
return 0;
}
public void printMessage(){
}
}
薯条的基类:
package Kfc;
//薯条的基类
public abstract class Frenchfries {
//单价
public float price;
//口味
public String kind;
//数量
public int num;
public float totalPrice(){
return 0;
}
public void printMessage(){
}
}
接着实现具体的食物:
香辣汉堡:
package Kfc;
//香辣汉堡
public class XlHamburg extends Hamburg {
public XlHamburg(int num){
this.price = 14.0f;
this.kind = "香辣";
this.num = num;
}
public float totalPrice() {
return this.price * this.num;
}
public void printMessage(){
System.out.println("--"+this.kind+"风味汉堡 \t单价:"+this.price+
" \t数量:"+this.num+" \t合计:"+this.totalPrice());
}
}
可乐:
package Kfc;
public class Klbeverage extends Beverage {
public Klbeverage(int num){
this.price = 7.0f;
this.kind = "可乐";
this.num = num;
}
public float totalPrice() {
return this.price * this.num;
}
public void printMessage(){
System.out.println("--"+this.kind+"风味可乐 \t单价:"+this.price+
" \t数量:"+this.num+" \t合计:"+this.totalPrice());
}
}
奥尔良鸡翅:
package Kfc;
import java.io.File;
//奥尔良鸡翅
public class AelChickenwarnings extends Chickenwarnings {
public AelChickenwarnings(int num){
this.price = 2.5f;
this.kind = "奥尔良";
this.num = num;
}
public float totalPrice() {
return this.price * this.num;
}
public void printMessage(){
System.out.println("--"+this.kind+"风味鸡翅 \t单价:"+this.price+
" \t数量:"+this.num+" \t合计:"+this.totalPrice());
}
}
番茄薯条:
package Kfc;
public class FqFrenchfries extends Frenchfries {
public FqFrenchfries(int num){
this.price = 8.0f;
this.kind = "番茄";
this.num = num;
}
public float totalPrice() {
return this.price * this.num;
}
public void printMessage(){
System.out.println("--"+this.kind+"风味薯条 \t单价:"+this.price+
" \t数量:"+this.num+" \t合计:"+this.totalPrice());
}
}
创建工厂,实现生产食物:
Abstractory 抽象工厂
package Kfc;
public interface Abstractory {
//生产汉堡
Hamburg productHamburg(int num);
//生产鸡翅
Chickenwarnings productChickenwarnings(int num);
//生产薯条
Frenchfries productFrenchfries(int num);
//生产饮料
Beverage productBeverage(int num);
}
Kfcfactory 具体工厂
package Kfc;
public class Kfcfactory implements Abstractory {
@Override
//生产香辣汉堡
public Hamburg productHamburg(int num) {
return new XlHamburg(num);
}
@Override
//生产奥尔良鸡翅
public Chickenwarnings productChickenwarnings(int num) {
return new AelChickenwarnings(num);
}
@Override
//生产番茄味薯条
public Frenchfries productFrenchfries(int num) {
return new FqFrenchfries(num);
}
@Override
//生产可乐
public Beverage productBeverage(int num) {
return new Klbeverage(num);
}
}
创建顾客类,实现点餐(也就是给工厂传入点餐信息的类,与main类是依赖关系)
Customer:
package Kfc;
//客户端
public class Customer {
//将来传进来的Abstractory(工厂)不同,那么生产的产品族也就不相同
private Abstractory factory;
/**
* 通过构造函数赋值工厂
* @param factory
*/
public Customer(Abstractory factory){
this.factory = factory;
}
//订购汉堡
public float orderHamburg(int num){
//生产汉堡
Hamburg hamburg = factory.productHamburg(num);
//打印订单
hamburg.printMessage();
//返回价格
return hamburg.totalPrice();
}
//订购鸡翅
public float orderChickenwarnings(int num){
//生产鸡翅
Chickenwarnings chickenwarnings = factory.productChickenwarnings(num);
//打印订单
chickenwarnings.printMessage();
//返回价格
return chickenwarnings.totalPrice();
}
//订购薯条
public float orderFrenchfries(int num){
//生产薯条
Frenchfries frenchfries = factory.productFrenchfries(num);
//打印订单
frenchfries.printMessage();
//返回价格
return frenchfries.totalPrice();
}
//订购可乐
public float orderBeverage(int num){
//生产薯条
Beverage beverage = factory.productBeverage(num);
//打印订单
beverage.printMessage();
//返回价格
return beverage.totalPrice();
}
/**
* 后期可以在这里添加用户点的套餐功能
*/
public float orderSetMeal_1(int num){
Hamburg hamburg = factory.productHamburg(1);
Chickenwarnings chickenwarnings = factory.productChickenwarnings(2);
Beverage beverage = factory.productBeverage(1);
float i = (hamburg.totalPrice() + beverage.totalPrice() + chickenwarnings.totalPrice()) - 6;
System.out.println("套餐一:香辣汉堡 1 个 + 奥尔良鸡翅 2 个 + 可乐 1 瓶\t价格:" +
i + "元" + "\t数量:" + num +"\t合计:" + num * i + "元");
return num * i;
}
public float orderSetMeal_2(int num){
Chickenwarnings chickenwarnings = factory.productChickenwarnings(2);
Beverage beverage = factory.productBeverage(1);
Frenchfries frenchfries = factory.productFrenchfries(1);
float i = (chickenwarnings.totalPrice() + beverage.totalPrice() + frenchfries.totalPrice()) - 5;
System.out.println("套餐二:奥尔良鸡翅 2 个 + 可乐 1 瓶 + 番茄薯条 1 包\t价格:" +
i + "元" + "\t数量:" + num +"\t合计:" + num * i + "元");
return num * i;
}
}
main类:(实现菜单的构造,以及选餐,打印小票的开头部分与结尾部分等控制台的操作)
小票的点餐内容打印实在点餐时实现打印(有第二个包实现,也就是策略模式中,在选择策略后,打印。最后由main类中的打印小票实现结尾打印)
client(main类):
package Kfc;
import strategypattern.*;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.util.*;
//到店点餐
public class Client {
//购买数量
static int num;
//最后的总价格
private static float price;
//用户付的钱
private static float pay;
private static Scanner input = new Scanner(System.in);
private static Abstractory factory = new Kfcfactory();//用于抽象工厂模式
private static SelectHandler sh = new SelectHandler();//用于策略模式
private static Price p; //用于策略模式中选择的设置
//静态代码块,类实例化是运行
static {
p = new FirstPrice();
}
private static Customer customer = new Customer(factory);
private static void menu(){
System.out.println("欢迎来到KFC点餐!");
System.out.println("*****按(1)进入点餐*****");
System.out.println("*****按(0)退出系统*****");
}
private static void menu1(){
System.out.println("我们有:\n" +
"(1)香辣汉堡 单价:14.0元\n"+
"(2)奥尔良鸡翅 单价: 2.5元\n"+
"(3)可乐 单价: 7.0元\n"+
"(4)番茄薯条 单价: 8.0元\n"+
"(5)套餐一:香辣汉堡 1 个 + 奥尔良鸡翅 2 个 + 可乐 1 瓶 价格: 20元\n"+
"(6)套餐二:奥尔良鸡翅 2 个 + 可乐 1 瓶 + 番茄薯条 1 包 价格: 15元\n");
System.out.println("您要选择购买的是?");
}
//进入系统选择函数
private static int select(){
while(true){
String s = input.next();
if(s.length() == 1 && ('1' == s.charAt(0) || '0' == s.charAt(0))){
return Integer.parseInt(s);
}
else{
System.out.println("无此选项,请重新输入!");
}
}
}
//选择判断函数
private static int select1(){
while(true){
String s = input.next();
if(s.length() == 1 && s.charAt(0) >= '1' && s.charAt(0) <= '6'){
return Integer.parseInt(s);
}
else{
System.out.println("无此选项,请重新输入!");
}
}
}
//计算价格
private static void price(int i){
switch(i){
case 1:
System.out.println("您要购买的个数是?");
num = input.nextInt();
p = new FirstPrice(); //设置为第一个结账算法
sh.setP(p);
price += sh.price(num,customer);//传入实参,进行结账
//后期可能会调用打印订单功能
sh.print_to_file(num);
break;
case 2:
System.out.println("您要购买的个数是?");
num = input.nextInt();
p = new SecondPrice();
sh.setP(p);
price += sh.price(num,customer);
//订单
sh.print_to_file(num);
break;
case 3:
System.out.println("您要购买的个数是?");
num = input.nextInt();
p = new TirdPrice();
sh.setP(p);
price += sh.price(num,customer);
sh.print_to_file(num);
break;
case 4:
System.out.println("您要购买的个数是?");
num = input.nextInt();
p = new ForthPrice();
sh.setP(p);
price += sh.price(num,customer);
//订单
sh.print_to_file(num);
break;
case 5:
System.out.println("您要购买的个数是?");
num = input.nextInt();
p = new FifthPrice();
sh.setP(p);
price += sh.price(num,customer);
sh.print_to_file(num);
break;
case 6:
System.out.println("您要购买的个数是?");
num = input.nextInt();
p = new SixthPrice();
sh.setP(p);
price += sh.price(num,customer);
sh.print_to_file(num);
break;
default:
System.out.println("没有这个选项,请重新输入!");
break;
}
}
//模拟打印小票的功能
private static void printbegin(){
try {
//重载实现字符串追加功能
FileWriter fw = new FileWriter("word.txt");
fw.write("\t\t\t欢迎您的光临\r\n");
fw.write("产品" + "\t\t\t数量" + "\t\t小计\r\n");
fw.write("-------------------------------------------------------------\r\n");
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//结尾部分票
private static void printend(){
try {
//重载实现字符串追加功能
FileWriter fw = new FileWriter("word.txt",true);
Date date = new Date();
//获取时间格式器
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.SHORT);
fw.write("-------------------------------------------------------------\r\n");
fw.write("\t打折优惠后\r\n");
fw.write("\t\t\t合计:" + "\t\t" + String.valueOf(price) + "\r\n");
fw.write("应收:" + String.valueOf(price) + "\r\n");
fw.write("收您:" + String.valueOf(pay) + "\r\n");
fw.write("找零:" + String.valueOf(pay - price) + "\r\n");
fw.write("订单时间:" + df.format(date) + "\r\n");
fw.write("欢迎您的下次光临!!!" + "\r\n");
fw.write("客服电话:18700183736" + "\r\n");
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//实现每个月的某一天打折促销活动的优惠活动
private static float date(){
Calendar calendar = Calendar.getInstance();
int date = calendar.get(Calendar.DATE);
if(12 == date){
System.out.println("今日是12号,本店全部打折0.5折哦!!!");
return 0.5f;
}
return 1.0f;
}
//找零辅助函数
private static void back(){
//日期若判断为指定天则打折;
price = date() * price;
while(true){
System.out.println("您需要支付" + price + "元!");
System.out.println("您打算支付多少钱?");
pay = input.nextFloat();
if(pay >= price){
System.out.println("找您" + (pay - price) + "元!");
break;
}
else{
System.out.println("不要耍赖哦!");
}
}
}
//支付与找零
private static void pay(){
int i;
System.out.println("请选择优惠卷:(0)满50减25,满100减35(1)未满足条件");
i = select();
if(price >= 50 && i == 0){
if(price >= 100){
price -= 35;
}
else{
price -= 25;
}
back();
}
else if(i == 1){
back();
}
else{
System.out.println("您未购置满50元需原价付款!");
back();
}
}
public static void main(String[] args){
int i; //进行选项
int flag = 1; //flag是外层循环结束标志,flag1是内层
int flag1 = 1;
while(1 == flag){
menu();
flag = select();
//这里如果选择退出,直接退
if(0 == flag){
break;
}
//调用打印小票函数
printbegin();
while(1 == flag1 && 1 == flag){
menu1();
i = select1();
price(i);
System.out.println("是否继续购买?(1)Yes(0)No");
flag1 = select();
if(0 == flag1){
pay(); //付钱
//付完钱就打印小票
printend();
flag1 = 1;
break;
}
}
}
}
}
package strategypattern第二个包实现策略模式
Price接口:(将来实现返回价格,以及打印点餐内容的就是它)
实现接口的六种策略,如下:
FirstPrice:
package strategypattern;
import Kfc.Customer;
import java.io.FileWriter;
import java.io.IOException;
public class FirstPrice implements Price {
private float price;
@Override
public float price(int num, Customer customer) {
this.price = customer.orderHamburg(num);
return price;
}
@Override
public void print_to_file(int num) {
//实现
try{
FileWriter fw = new FileWriter("word.txt",true);
fw.write("香辣汉堡" + "\t\t" + String.valueOf(num) + "\t\t" + String.valueOf(price) + "\r\n");
fw.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
SecondPrice:
package strategypattern;
import Kfc.Customer;
import java.io.FileWriter;
import java.io.IOException;
public class SecondPrice implements Price{
private float price;
//这里是第二个选择,也就是买鸡翅
public float price(int num, Customer customer){
this.price = customer.orderChickenwarnings(num);
return price;
}
@Override
public void print_to_file(int num) {
//实现
try{
FileWriter fw = new FileWriter("word.txt",true);
fw.write("奥尔良鸡翅" + "\t\t" + String.valueOf(num) + "\t\t" + String.valueOf(price) + "\r\n");
fw.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
ThirdPrice:
package strategypattern;
import Kfc.Customer;
import java.io.FileWriter;
import java.io.IOException;
public class TirdPrice implements Price{
private float price;
//这里是第三个选择,购买可乐
public float price(int num, Customer customer){
this.price = customer.orderBeverage(num);
return price;
}
@Override
public void print_to_file(int num) {
//实现
try{
FileWriter fw = new FileWriter("word.txt",true);
fw.write("可乐" + "\t\t\t" + String.valueOf(num) + "\t\t" + String.valueOf(price) + "\r\n");
fw.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
ForthPrice:
package strategypattern;
import Kfc.Customer;
import java.io.FileWriter;
import java.io.IOException;
public class ForthPrice implements Price {
private float price;
//这是第四个选择,购买薯条
@Override
public float price(int num, Customer customer) {
this.price = customer.orderFrenchfries(num);
return price;
}
@Override
public void print_to_file(int num) {
//实现
try{
FileWriter fw = new FileWriter("word.txt",true);
fw.write("番茄薯条" + "\t\t" + String.valueOf(num) + "\t\t" + String.valueOf(price) + "\r\n");
fw.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
FifthPrice:
package strategypattern;
import Kfc.Customer;
import java.io.FileWriter;
import java.io.IOException;
public class FifthPrice implements Price {
private float price;
//第五个选择,购买套餐一
@Override
public float price(int num, Customer customer) {
this.price = customer.orderSetMeal_1(num);
return price;
}
@Override
public void print_to_file(int num) {
//实现
try{
FileWriter fw = new FileWriter("word.txt",true);
fw.write("套餐一" + "\t\t\t" + String.valueOf(num) + "\t\t" + String.valueOf(price) + "\r\n");
fw.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
SixthPrice:
package strategypattern;
import Kfc.Customer;
import java.io.FileWriter;
import java.io.IOException;
public class SixthPrice implements Price {
private float price;
//这是第六个选择,购买套餐二
@Override
public float price(int num, Customer customer) {
this.price = customer.orderSetMeal_2(num);
return price;
}
@Override
public void print_to_file(int num) {
//实现
try{
FileWriter fw = new FileWriter("word.txt",true);
fw.write("套餐二" + "\t\t\t" + String.valueOf(num) + "\t\t" + String.valueOf(price) + "\r\n");
fw.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
最后一个类SelectHandler类(实现设置策略种类,就是设置选择的是哪个策略,将来有新的策略添加,也可以通过它来设置,为的是代码统一,以及满足开闭原则)
SelectHandler:
package strategypattern;
import Kfc.Customer;
public class SelectHandler {
private Price p;
//设置选择第几个选项
public void setP(Price p) {
this.p = p;
}
//这里返回的就是所有的钱了
public float price(int num,Customer customer){
return p.price(num, customer);//p的不同势必导致买到的东西不同
}
//用于将订单信息存入文件
public void print_to_file(int num){
p.print_to_file(num);
}
}
四、总结
这次的点餐系统除了加深我对设计模式的理解外,我觉得最重要的是我通过这次的点餐制作对面向对象编程的真实意义才算有所了解了,以前以为自己用的是面向对象的语言就觉的是在面向对象编程了,现在我认为,面向对象编程是为了能更好的服务用户,同时在添加新功能的时候可以方便的添加或修改部分代码就可以了。而不是牵一发动全身!
除了这些之外,就是Java的基础知识的增强了,比如,对日期类的使用,和熟练使用文件操作打印小票。也知道了文件操作时最后最好关闭文件流,否则会出现写不进数据的情况!再者还有测试代码的编写!