java超市管理系统1.0(含源文件,后续会继续优化~)
程序概述:小型超市商品销售管理系统选择小型超市的四类商品进行管理。这四类商品是:食品、化妆品、生活用品和饮料(四个类)。每类商品都包含有商品名和商品利润(其中包括商品的售价、进价、库存量)。(五个属性)每类不同的商品还有区别于其他商品的特殊信息(子类特有属性)例如,食品有批发商,化妆品有品牌,饮料有生产厂家。
上述文字可以确定以下几点
上文提及到:我们需要定义四个类分别表示四类商品,那么我们在写之前是否可以从四个类抽取它们相同的特点(属性)来引入继承的思想呢?
显然是可以的,我们可以定义一个商品类Wares作为父类,(并且使用多态来切换父类引用的不同指向)Wares父类包含了四个类商品的共性(具有商品名、售价、进价、库存量、商品编号id这五个属性),而其子类当然就是食品Food、化妆品Cosmetic、生活用品DailyUsing和饮料Drinking,这样程序中的类就确定下来了
我们可以再深入思考一下:Wares可以是普通类、可以是抽象类,我们如何去选择呢?
其实两者在功能实现上都是可以的,但是普通类实现接口的时候,是一定要重写接口中每一个方法的,而抽象类却不需要;况且Wares是四类商品的父类,我们在对商品进行操作的时候,只需要操作其子类的对象即可,没有必要实例化Wares对象,因此我们选择将Wares定义为抽象类。
关于四个子类:食品类Food、饮料类Drinking、化妆品类Cosmetic、生活用品类DailyUsing的确定
四个子类只需要继承父类Wares即可,共性属性自然而然的继承了下来,特性属性在每个类中单独编写即可。
//Wares类中的属性//商品名字privateStringname;//商品编号privateintid;//商品进价privatedoubleinPrice;//商品售价privatedoubleoutPrice;//库存量privateintCount;
注:Wares及其子类的属性我们最好都设为私有属性,再去通过setter和getter方法进行存取,养成封装的好习惯~
商品类Wares会包含所以商品类及其子类所共有的静态特征(属性)和对商品的动态操作(方法),属性在类中一一初始化即可,但是方法我们也要在此类中一一写出方法体吗?
下面我们来根据程序需求来确定方法(需求:增删改查、显示利润)
我们还可以加入“遍历所有商品”功能,这样还可以在程序调试的时候,判断是否可以真正实现增删改查功能,起到验证作用
因此我们确定下来了有以下几个方法:
本程序我们自定义equals()判定规则为:当对象的编号和名称同时相同时,判定两个对象为同一个对象很显然,本程序无论是“增删改查”操作这四个基本功能,还是验证用户是否重复添加同一商品这一功能,都需要两个对象进行equals比较,因此重写equals()是必须的。
那么是否每一个类都需要重写equals方法呢?
显然,Wares抽象类是不需要的,因为我们在比较的时候,是比较其子类的对象是否是同一对象,而并非父类对象(况且该父类是抽象类,无法实例化对象,更别谈可以调用其equals()了)因此我们可以确定:要重写Food类、Drinking类、DailyUsing类、Cosmetic类中的equals()要进行重写
/*重写equals方法自定义为:当名称相同且商品id相同的时候,视为同一件商品*/@Overridepublicbooleanequals(Objecto){if(this==o)returntrue;if(o==null||!(oinstanceofWares))returnfalse;Cosmeticcosmetic=(Cosmetic)o;returnsuper.getName().equals(cosmetic.getName())&&super.getId()==cosmetic.getId();}2.重写toString吗?由于需要清晰的显示商品信息,每一次需要输出信息的时候,可以System.out.print(“…”+属性1+“…”+属性2);来显示每一条信息。
但是鉴于本程序输出的次数很多,而且System.out.print()方法在内部调用toString()。
因此我们可以重写(父类)toString方法,使得每次的输出都有一套固定的输出格式,实现了System.out.print(实例化的对象名);即可完成格式化输出。
那么是否每一个类都需要重写toString()呢?
显然,Wares抽象类是不需要的,因为我们输出信息的时候,是要输出四个子类对象的信息(父类Wares是抽象类,无法实例化对象,更别谈可以调用其toString()了)因此我们可以确定:要重写Food类、Drinking类、DailyUsing类、Cosmetic类中的toString()要进行重写
/*重写toString方法*/@OverridepublicStringtoString(){return"化妆品{\t"+super.getId()+"\t"+super.getName()+"\t\t"+super.getInPrice()+"元"+"\t\t"+super.getOutPrice()+"元"+"\t\t"+super.getCount()+"件"+"\t}";}3.重写hashCode()吗?Java中规定:如果两个对象相同,那么它们的hashCode值一定要相同;如果两个对象的hashCode相同,它们对象本身equals比较并不一定相同。因此如果改写了equals方法,令两个实际不是一个对象的两个实例在逻辑上相等了,但是hashcode却是不等,这是有矛盾的。
这种矛盾会在hashMap等集合中造成实际运行结果和预期运行结果的不一致产生。(个人理解:equals()返回true表示两个对象相同,在同一个单向链表上比较那么对于同一个单向链表上的结点来说,他们的哈希值都应该是相同的所以hashCode()的返回值也应该相同)。
就本程序来说没有用到hashMap这样集合底层的数据结构来存储每一个对象(而是用的arrayList),因此是否重写hashCode方法对本程序的影响不大,但是鉴于程序的规范性,还是应该遵循以下原则:
如果一个类的equals方法重写了,那么hashCode方法必须重写。并且equals方法返回如果是true,hashCode方法返回的值必须一样。
/*重写hashCode方法*/@OverridepublicinthashCode(){returnObjects.hash(brand);}4.存储结构的确定类、接口、方法、属性、数据类型以及实现方法都已经确定了,现在需要把实例化的对象以什么样的形式存储到一起呢?
一种是数组、一种是集合
很显然,我们在进行初始化的时候,不知道需要存入多少商品,无法对数组进行预估计容量;数组只能存放单一数据类型的元素,在对其操作的时候(相比较集合中已提供了对集合的很多操作而言)很不方便,而且数组虽然检索效率高,但是插入查找效率很低。
本程序我们选择arrayList集合进行对象的存储。
注:就本程序而言,个人感觉还是使用hashMap(查询更加快捷)或hashSet(排序更加便捷),且两者都可以自动控制存储的信息无重复的特点。这是本程序需要改进的地方之一