思路介绍

KFC模拟系统各个角色职责如下:

顾客:看菜单并通知给职工、付钱

职工:职工把菜单给中介、计算价格、打印小票

KFC中介:中介对应通知单品工厂或套餐工厂生产

1个实体工厂(生产间):生产所有的单品食物。

2个套餐工厂(生产间):一个工厂生产一个套餐。

单品实体创建(简单工厂模式)、套餐实体(抽象工厂模式)、优惠券(策略模式)

KFC肯德基分店与集团的架构 肯德基有几个部门_KFC肯德基分店与集团的架构

KFC肯德基分店与集团的架构 肯德基有几个部门_实例化_02

KFC肯德基分店与集团的架构 肯德基有几个部门_实例化_03

源码

单品:简单工厂

public interface singlefactory {
	public Hamberger   produceHamberger(int order2,int num);
	public FrenchFried produceFrench(int order2,int num);
	public Chicken     produceChicken(int order2,int num);
	public drinkings   producedrinking(int order2,int num);
}
package singlefoodfactory;
import singlefood.*;
/**
 * 简单工厂,负责生产所有的单品
 * @author 万物甦醒
 *
 */
public class SingleFoodFactory implements singlefactory{
	@Override //汉堡类
	public Hamberger produceHamberger(int order2, int num) {
		switch(order2)
		{
			case 1:return new Hamberger1(num);
			case 2:return new Hamberger2(num);
			case 3:return new Hamberger3(num);
		}
		return null;
	}
	@Override //薯条类
	public FrenchFried produceFrench(int order2, int num) {
		switch(order2)
		{
			case 1:return new FrenchFried1(num);
			case 2:return new FrenchFried2(num);
			case 3:return new FrenchFried3(num);
		}
		return null;
	}
	@Override //鸡肉类
	public Chicken produceChicken(int order2, int num) {
		switch(order2)
		{
			case 1:return new Chicken1(num);
			case 2:return new Chicken2(num);
		}
		return null;
	}

	@Override //饮品类
	public drinkings producedrinking(int order2, int num) {
		switch(order2)
		{
			case 1:return new drinkings1(num);
			case 2:return new drinkings2(num);
		}
		return null;
	}
}
package combofactory;

/**
 * 套餐接口,相当于抽象工厂的工厂接口
 * 该接口由多继承其他接口,
 * price接口以便业务层接口回调时能够获得套餐的一些信息如产品价格
 * num接口是以便业务层接口回调时能够获得所需要生产的数量
 */
import singlefood.Chicken;
import singlefood.FrenchFried;
import singlefood.Hamberger;
import singlefood.drinkings;

public interface Combo extends num,price{
	public Hamberger   produceHamberger();
	public FrenchFried produceFrench();
	public Chicken     produceChicken();
	public drinkings   producedrinking();
	public String      Message();
}
package combofactory;
/**
 * 套餐一:香辣鸡腿堡+小份薯条+鸡米花+可乐(30.0)
 * 每个套餐类似于一个工厂,负责创建属于该工厂系的产品(采用抽象工厂模式)
 */

import singlefood.Chicken;
import singlefood.Chicken1;
import singlefood.Chicken2;
import singlefood.FrenchFried;
import singlefood.FrenchFried1;
import singlefood.Hamberger;
import singlefood.Hamberger1;
import singlefood.drinkings;
import singlefood.drinkings1;


public class Combo1 implements Combo {
	private int num; //套餐的数量  
	@Override
	public Hamberger produceHamberger() {
		return new Hamberger1(num);
	}
	@Override
	public FrenchFried produceFrench() {
		return new FrenchFried1(num);
	}
	@Override
	public Chicken produceChicken() {
		return new Chicken1(num); 
	}
	@Override
	public drinkings producedrinking() {
		return new drinkings1(num);
	}
	//计算套餐的价格
	@Override
	public float totolprice() {
		return 30*num;
	}
	//得到套餐的数量
	@Override
	public void setnum(int num) {
		this.num= num;
	}
	@Override
	public String Message() {
		return "套餐1:香辣鸡腿堡+小份薯条+鸡米花+可乐 "+"  数量:"+ num +"  价格:"+totolprice()+"\r\n";
	}

}

```java
package combofactory;
/**
 * 套餐二:奥尔良鸡腿堡鸡腿堡+大份薯条+香辣鸡翅+可乐(38.0)
 * 每个套餐类似于一个工厂,负责创建属于该工厂系的产品(采用抽象工厂模式)
 */

import singlefood.Chicken;
import singlefood.Chicken1;
import singlefood.Chicken2;
import singlefood.FrenchFried;
import singlefood.FrenchFried1;
import singlefood.FrenchFried3;
import singlefood.Hamberger;
import singlefood.Hamberger1;
import singlefood.Hamberger2;
import singlefood.drinkings;
import singlefood.drinkings1;


public class Combo2 implements Combo {
	private int num;  //套餐的数量
	//依次创建套餐里的各类产品
	@Override
	public Hamberger produceHamberger() {
		return new Hamberger2(num);
	}
	@Override
	public FrenchFried produceFrench() {
		return new FrenchFried3(num);
	}
	@Override
	public Chicken produceChicken() {
		return new Chicken2(num); 
	}
	@Override
	public drinkings producedrinking() {
		return new drinkings1(num);
	}
	//计算套餐的价格
	public float totolprice() {
		return 30*num;
	}
	//得到套餐的数量
	public void setnum(int num) {
		this.num= num;
	}
	@Override
	public String Message() {
		return "套餐2:奥尔良鸡腿堡鸡腿堡+大份薯条+香辣鸡翅+可乐"+"  数量:"+ num +"  价格:"+totolprice()+"\r\n";
	}
}

```java
package kfcsystem;
import combofactory.Combo;
import singlefood.foodBase;
import singlefoodfactory.SingleFoodFactory;
/**
 * KFCmedium相当于通知单品包间或套餐保健应该生产什么东西,并得到包间生产后的东西
 * KFCmedium相当于中介经理,一方面通知包间的生产,另一方面把生产后的给职工(职工需要计算价格)
 * @author 万物甦醒
 *
 */
public class KFCmedium {
	private foodBase food = null;	//从单品包间生产出来的食品对象
	private Combo combo = null;     //从套餐生产间生产出来的套餐对象
	/**
	 * 根据用户所选的产品种类交给单品生产包间生产并返回生产后的单品
	 * @param order1 单品所对应在菜单种类的标号
	 * @param order2 单品在对应种类里的标号
	 * @param num   单品的数量
	 */
	public foodBase createSinglefood(int order1,int order2,int num) 
	{
		SingleFoodFactory factory = new SingleFoodFactory();//实例化单品工厂
		try {
			if(order1 == 1)//汉堡类
			{
				//创建具体的汉堡对象
				food = factory.produceHamberger(order2, num);
			}
			else if(order1 == 2)//薯条类
			{
				//创建相应的薯条对象
				food = factory.produceFrench(order2, num);
			}
			else if(order1 == 3) //鸡肉类
			{
				//创建相应的鸡肉对象
				food = factory.produceChicken(order2, num);
			}
			else if(order1 ==4 ) //饮品类
			{
				//创建相应的饮品对象
				food = factory.produceChicken(order2, num);
			}
		}catch (Exception e) {
			System.out.println("输入有误 "+e.getMessage());
			return food;
		}
		return food;
	}
	/**
	 * 通知相应的生产套餐生产间生产套餐
	 * @param order2 套餐的种类
	 * @param num	 套餐的数量
	 * @return       套餐对象
	 * @throws Exception
	 */
	public Combo createCombo(int order2 ,int num) throws Exception
	{
		//以字符串形式保存套餐名
		String comboName = "combofactory.Combo"+String.valueOf(order2).trim();
		//利用反射机制创建套餐对象
		Class c = Class.forName(comboName);	//实例化Class对象
		combo=(Combo) c.newInstance();	    //实例化对象并强制转换为具体combo对象
		combo.setnum(num);
		return combo;
	}
	
}

```java
package kfcsystem;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;

import javax.print.attribute.standard.RequestingUserName;

import org.omg.CORBA.PUBLIC_MEMBER;

import Dao.customerImpl;
import Discount.Discount;
import Discount.DiscountHandle;
import Discount.DiscountTicket;
import Discount.PromotionActivity;
import Util.TimeUtil;
import combofactory.Combo;
import singlefood.foodBase;
/**
 * 负责依次获取顾客所点地点,传递给kfcMedium
 * 然后把食物依次传回到职员手中,职员传递给顾客
 *(其中生产后的食物对象放入集合容器之中,返回整个容器(即所有点的食物)给顾客)
 */
public class Clerk {
	private float price;		//职员计算顾客总的价格
	private float money;		//顾客给的钱
	private float discountmoney;//折后价
	private float backmoney;    //找零
	private String purchasetime;		//计入顾客消费的时间
	
	private ArrayList<foodBase> foodmenu = new ArrayList<>();   //实例化ArrayList接口,用于存储食物容器,并将其返回给顾客
	private ArrayList<Combo> combolist  = new ArrayList<>();     //实例化ArrayList接口,用于存储套餐容器
	private foodBase singlefood = new foodBase();				//从(食品包间)生产出来的返回给职员食品对象
	private Combo combo =null; //生产后的套餐对象
	private KFCmedium kfCmedium =new KFCmedium();   		 //声明kfc实体店,将菜单传给该实体店
	private  DiscountTicket ticket = new DiscountTicket();  //实例化优惠券对象
	//该方法负责接收顾客点的单
	public void getorder(int order1,int order2, int num) throws Exception
	{
		//将顾客所点地单地号码传递给KFC中介,并得到从工厂返回到的单品或套餐
		if(order1>0 && order1<=4)
		{
			singlefood=kfCmedium.createSinglefood(order1, order2, num);
			//将生产后的单品食物添加入单品容器中
			foodmenu.add(singlefood);
		}
		else if(order1 == 5)
		{
			combo= kfCmedium.createCombo(order2, num);
			//将生产后的套餐放入套餐容器中
			combolist.add(combo);
		}
	}
	//该方法用于统计顾客所应付的钱 
	public  void  calculateprice() throws Exception {
		float totol = 0;
		if(singlefood !=null)
		{
			Iterator<foodBase> iterator1 = foodmenu.iterator();//实例化迭代器,用于计算食物的价格
			//计算所有单品的价格
			while(iterator1.hasNext())
			{
				foodBase next = iterator1.next();
				totol += next.totolprice();
			}
		}
		
//		if(combo != null)
//		{
			Iterator<Combo> iterator2 = combolist.iterator();  //实例化迭代器,用于计算套餐的价格
			//计算套餐的价格
			while(iterator2.hasNext())
			{
				Combo next = iterator2.next();
				totol += next.totolprice();
			}
//		}
		price = totol;	//应付价格(打折前)
	}
	
	//计算使用优惠券后的价格
	public void useticket(int n, float m) throws Exception {
		discountmoney=ticket.useTicket(n, m);
	}
	//计算是否在活动期间
	public void inpromotion()
	{
		if(PromotionActivity.promoteright()==true)
		{
			System.out.println("感谢你在22:00~24:00消费 ,为你九折优惠");
			discountmoney=PromotionActivity.promote(discountmoney);
		}
	}
	public void PrinterMessage() {
		String filename = "xiaopiao.txt";
		File file = new File(filename); //实例化文件对象
		Iterator<foodBase> iterator1 = foodmenu.iterator();//实例化迭代器食物
		Iterator<Combo> iterator2 = combolist.iterator();  //实例化迭代器套餐
		try {
			OutputStream os = new FileOutputStream(file,true);//声明输出流文件并实例化文件流对象
			while(iterator1.hasNext())
			{
				byte[] by = iterator1.next().printMessage().getBytes();//把获取的信息字符串转化为字节数组
				os.write(by);//将字节数组里的内容一次性写入文件中
			}
			while(iterator2.hasNext())
			{
				byte[] by = iterator2.next().Message().getBytes();//把获取的信息字符串转化为字节数组
				os.write(by);//将字节数组里的内容一次性写入文件中
			}
			String string ="每天22:00~24:00消费可享九折优惠    "+"\r\n"+"折前价:  "+price+"  折后价:" +discountmoney+ "   实付:  "+money+"   找零:  "+backmoney+"\r\n"
			+"祝你消费愉快!!   "+ purchasetime +"\r\n"+"\r\n"+"\r\n";
			byte[] by = string.getBytes();
			os.write(by);
			
			os.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	/**
	 * 该方法负责将生产后的食物传给顾客,将单品和套餐一起给顾客
	 * 返回一个单品的集合,该方法是吧套餐集合里的单品对象提取出来并把它添加到单品集合foodmenu中
	 */
	public void packagefood()
	{
		Iterator<foodBase> iterator1 = foodmenu.iterator();		//实例化迭代器  单品
		Iterator<Combo> iterator2 = combolist.iterator();  //实例化迭代器  套餐
		while(iterator2.hasNext())
		{
			Combo next = iterator2.next();//获取套餐对象
			//获取套餐中的食物,并将食物加入单品容器中,相当于最后给顾客的是单品容器,因为套餐也是由单品构成
			foodmenu.add(next.produceChicken());
			foodmenu.add(next.produceHamberger());
			foodmenu.add(next.producedrinking());
			foodmenu.add(next.produceFrench());
		}
	}
	//将折前价格告诉给顾客
	public float getPrice() {
		return this.price;
	}
	//把折后价告诉给顾客
	public float discountPrice() {
		return this.discountmoney;
	}
	//找零
	public float payback(float money) {
		this.money=money;
		backmoney = money - discountmoney;
		return backmoney;		
	}
	//将单品食物集合返回给顾客
	public ArrayList<foodBase> getFoodmenu() {
		return foodmenu;
	}
	//信息写入数据库
	public void preserveInfo()
	{
		customerImpl cus = new customerImpl();
		TimeUtil time = new TimeUtil();
		purchasetime = time.gettime();      //获取时间
		cus.executeDao(purchasetime, discountPrice());//写入数据库
	}
	
}

```java
package kfcsystem;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
/**
 * 顾客负责阅读菜单、点餐给职员Clerk、付钱、收到小票
 * 通过集合容器存储各种
 */
import java.util.Scanner;

import Discount.DiscountTicket;
import Discount.PromotionActivity;
import singlefood.food;
import singlefood.foodBase;

public class Customer {
	
	private static Scanner scan = new Scanner(System.in );
	private static Clerk clerk = new Clerk();
	private static foodBase food = new foodBase();
	private static DiscountTicket ticket =new DiscountTicket();
	//实例化ArrayList接口,指定泛型为foodBase(单品食物基类),用于存储单品的集合
	private static ArrayList<foodBase> foodmenu = new ArrayList<>();  
	private static int order1; 	    //产品种类
	private static int order2;     	//产品号码
	private static int num;     	//产品数量
	private static float price;		//顾客所应付的价格
	private static boolean flag = true;
	private static String m;
	
	public static void main(String[] args) throws Exception {
		
		menu();		//顾客阅读菜单
		//顾客选择菜品
		while(flag)
		{
			System.out.println("请输入菜品类型(1汉堡类  2薯条类  3鸡肉类  4饮品类  5 套餐类)");
			order1=scan.nextInt();
			System.out.println("请选择序号");
			order2=scan.nextInt();
			System.out.println("请输入产品数量");
			num=scan.nextInt();
			//顾客将单传给职员
			clerk.getorder(order1, order2, num);

			System.out.println("继续点(Y or y),结账(N or n)");
			m = scan.next();
			flag = judgeprint(m);//判断顾客是否继续点单
		}
			
			//职工计算价格
			clerk.calculateprice();
			float m =clerk.getPrice();
			//使用优惠券
			ticketInfo();
			int n = scan.nextInt();
			System.out.println("");
			clerk.useticket(n,m);
			ticket.useTicket(n,m);
			//活动优惠
			clerk.inpromotion();
			//输出价格
			System.out.println("折前价为:"+m+" 折后价为" + clerk.discountPrice());
			
			//顾客给钱
			float money = 0;
			while(money < clerk.discountPrice())
			{
				System.out.println("未付款或金额不够,请(重新)付款");
				money=scan.nextFloat();
			}
			//clerk.payback(money);
			//职员找零
			System.out.println("找零 :  "+clerk.payback(money));
			//职员将信息写入数据库
			clerk.preserveInfo();
			//打印小票
			clerk.PrinterMessage();
			//职员打包食物(将套餐里的单品分出来)
			clerk.packagefood();
			System.out.println("顾客所能吃到的食物有"+clerk.getFoodmenu());
	}
	//输出优惠券信息
	private static void ticketInfo() {
		System.out.println("你使用  1.九折优惠券  2.八折优惠券   3.20元优惠券");
	}
	//判断输入是否得当
	private static boolean judgeprint(String m) {
		if (m.equalsIgnoreCase("y") )
		{
			return true;
		}
		return false;
	}
	//文件读入菜单
	static void menu() throws Exception
	{
		String pathname = "menu.txt"; 
		try (FileReader reader = new FileReader(pathname);
		     BufferedReader br = new BufferedReader(reader) // 建立一个对象,它把文件内容转成计算机能读懂的语言
		     ) {
		            String line;
		            while ((line = br.readLine()) != null) {
		                // 一次读入一行数据
		                System.out.println(line);
		            }
		        } catch (Exception e) {
		            e.printStackTrace();
		        }
	}
	//接收职工传来的单品
	public static void setFoodmenu(ArrayList<foodBase> foodmenu) {
		Customer.foodmenu = foodmenu;
	}
	//接收职工告诉的价格
	public static void setPrice(float price) {
		Customer.price = price;
	}
}

KFC肯德基分店与集团的架构 肯德基有几个部门_KFC点餐系统_04


KFC肯德基分店与集团的架构 肯德基有几个部门_Java_05

KFC肯德基分店与集团的架构 肯德基有几个部门_KFC点餐系统_06

心得

设计模式上,采用了简单工厂模式完成单品设计,但是当添加产品时,它的可维护性就差了。但如果相应抽象方法设计,不可否任能够遵守开闭原则,但是种类过多,每个实体类都要单独创建一个工厂也挺不方便的。套餐就很好的使用了抽象工厂方法,每个套餐相当于一个工厂,但也有所违反开闭原则。设计模式上仍然有一些问题需要去反思,顾客和职员耦合性过强,职员的指责过多,一个职员实现了太多的功能。