这次来写一个项目,这个项目很综合,之前的很多知识都用上了。我写了两遍,还是有些地方不能顺畅的写出来,发个博客防止遗忘思路。
先分析一波,超市收银系统都包含什么部分?
有电脑,酱油,香蕉,手机,等等各种商品,有一个放商品的仓库,还有一个收银系统
把商品抽象成一个类,具有名称,价格,数量,编号这几种属性。
仓库需要提供的功能有,存货,取货,进货。
收银系统需要有展示商品,收钱,打折这几种功能,因为打折每一天都不一样,有比例折扣,有满减折扣,所以把打折做成抽象类,提供一个抽象的打折方法。
商品部分最简单,先写这部分。
class ShangPin
{
public double Price
{
get;
set;
}
public double Count
{
get;
set;
}
public string Name
{
get;
set;
}
public string ID
{
get;
set;
}
public ShangPin(string name,double price,string id)
{
this.Name = name;
this.Price = price;
this.ID = id;
}
}
其他商品只需要继承这个父类即可。
然后来写仓库类。
那么,当我们创建仓库对象的时候,我们的货物就要存进去了,用什么来存货物呢?
用一个集合就可以存各种货物,不用考虑长度问题。但是用List<>集合,没有分类的情况下,这个集合中什么数据都有,好存不好取。那么如何做到分门别类的存呢?
我们可以在集合中存集合,在一个仓库中,放上很多货架,每一个货架放的商品都不同,这样我们在取货的时候,只要去取相对应货架上的物品,就没问题了。
List<List<ShangPin>> list = new List<List<ShangPin>>();
public CangKu()
{
list.Add(new List<ShangPin>());
list.Add(new List<ShangPin>());
list.Add(new List<ShangPin>());
list.Add(new List<ShangPin>());
}
接下来写两个方法,一个存货,一个取货,当调用存货方法的时候,货物被存储到货架上,调用取货方法的时候,货物被取出,并且货架上货物减少。
存货
我们在存货的时候,需要知道存的是什么,要存多少,所以要给这个方法提供两个参数,名字和数量。每次存的是什么,就创建一个这个商品的新的对象,把它存到相对应的货架(list[])上,用一个for循环依次存放。
public void CunHuo(string strType,int count)
{
for (int i = 0; i < count; i++)
{
switch (strType)
{
case "Acer":
list[0].Add(new Acer("宏基笔记本", 1000, Guid.NewGuid().ToString()));
break;
case "SanXing":
list[1].Add(new SanXing("三星手机", 500, Guid.NewGuid().ToString()));
break;
case "JiangYou":
list[2].Add(new JiangYou("酱油", 10, Guid.NewGuid().ToString()));
break;
case "Banana":
list[3].Add(new Banana("香蕉", 50, Guid.NewGuid().ToString()));
break;
}
}
}
取货
取货的时候我们需要得到货物,要得到什么货物,要多少,依然要提供给方法两个参数。取完货这些货物要放到哪里?
可以放在一个数组中,那么返回值就可以是一个商品父类的数组,因为你不知道要什么商品,但是返回一个父类肯定没有错误。一般我们从货架上拿东西,都是从前面拿,那么第二个商品就成为了第一个。所以可以理解为,我从货架的第一个位置拿商品,拿完之后我们把这个第一个商品的数据移除,这时原本第二个元素就变成了第一个元素,继续取货循环。
public ShangPin[] QuHuo(string strType,int count)
{
ShangPin[] sp = new ShangPin[count];
for (int i = 0; i < count; i++)
{
switch (strType)
{
case "Acer":
sp[i] = list[0][0];
list[0].RemoveAt(0);
break;
case "SanXIng":
sp[i] = list[1][0];
list[1].RemoveAt(0);
break;
case "JiangYou":
sp[i] = list[2][0];
list[2].RemoveAt(0);
break;
case "Banana":
sp[i] = list[3][0];
list[3].RemoveAt(0);
break;
}
}
return sp;
}
然后写一个商品展示的方法
这个很简单,用一个foreach循环就可以了
public void Show()
{
foreach (var item in list)
{
Console.WriteLine("超市有商品:" + item[0].Name + ",\t有" + item.Count + "个,\t每个" + item[0].Price + "元");
}
}
至此仓库类就写完了。
下面来写超市收银这个类
当我们创建超市类的时候,就要创建一个仓库对象,并且给仓库存上货物,并且因为在这里创建了仓库对象,那么我们可以在这里调用仓库类商品展示的方法,这样我们在主函数中只需要调用超市类商品展示的方法即可,不需要再创建仓库对象。
CangKu ck = new CangKu();
public SuperMarket()
{
ck.CunHuo("Acer", 1000);
ck.CunHuo("SanXing", 500);
ck.CunHuo("JiangYou", 100);
ck.CunHuo("Banana", 200);
}
public void Show()
{
ck.Show();
}
然后是核心部分了,与用户的交互,这里还要写两个方法,一个是算账,一个是获取打折方法。
先来看算账,这个很简单,一个循环得出总数就好了
public double GetMoney(ShangPin[] sp)
{
double realMoney = 0;
for (int i = 0; i < sp.Length; i++)
{
realMoney += sp[i].Price;
}
return realMoney;
}
然后是获取打折方法,这个用到了前两天学的简单工厂模型,因为不知道会是哪种打折,所以返回一个父类类型的子类打折对象肯定没错。
public DaZhe GetDz(string input)
{
DaZhe dz = null;
switch(input)
{
case "1":dz = new BuDaZhe();
break;
case "2":dz = new DaZheRate(0.9);
break;
case "3":dz = new DaZheMN(300, 50);
break;
}
return dz;
}
abstract class DaZhe
{
public abstract double GetTotalMoney(double realMoney);
}
class DaZheMN:DaZhe
{
public double M
{
get;
set;
}
public double N
{
get;
set;
}
public DaZheMN(double m,double n)
{
this.M = m;
this.N = n;
}
public override double GetTotalMoney(double realMoney)
{
if (realMoney >= this.M)
{
return realMoney - (int)(realMoney / this.M) * this.N;
}
else
{
return realMoney;
}
}
}
class DaZheRate : DaZhe
{
public double Rate
{
get;
set;
}
public DaZheRate(double rate)
{
this.Rate = rate;
}
public override double GetTotalMoney(double realMoney)
{
return realMoney * this.Rate;
}
}
class BuDaZhe : DaZhe
{
public override double GetTotalMoney(double realMoney)
{
return realMoney;
}
}
最后来写和用户的交互
public void Ask()
{
Console.WriteLine("买点啥?");
Console.WriteLine("我们有Acer,SanXing,JiangYou,Banana");
string strType = Console.ReadLine();
Console.WriteLine("要多少");
int count = Convert.ToInt32(Console.ReadLine());
ShangPin[] sp = ck.QuHuo(strType, count);
double realMoney = GetMoney(sp);
Console.WriteLine("请选择打折方式:1--不打折 2--打九折 3--满300-50");
string input = Console.ReadLine();
DaZhe dz = GetDz(input);
double totalMoney = dz.GetTotalMoney(realMoney);
Console.WriteLine("应付款{0}", totalMoney);
Console.WriteLine("小票如下");
foreach (var item in sp)
{
Console.WriteLine("货物名称:" + item.Name + ",\t货物单价:" + item.Price + ",\t货物编号:" + item.ID);
}
Console.ReadKey();
}
至此,所有的功能我们基本上都实现了,在主函数中调用使用。
SuperMarket sm = new SuperMarket();
sm.Show();
sm.Ask();
Console.WriteLine();
写到这,发现面向对象编程,主函数部分真的好简单,只需要调用方法,理清逻辑即可。
GUID
这个类可以帮助我们自动生成不一样的编号。
这是一个结构,并不允许我们创建他的对象,但是它提供了一个静态方法,可以返回一个新的guid对象。
Guid.NewGuid().ToString();