一、实验内容
随着家庭购买汽车的增加,停车场车位紧张的问题越来越突出。请根据题目要求完成简单的车位管理程序。
1.停车场有若干停车位(为说明问题,假定为n个,可扩),每个位置可以存放不同种类的的汽车,包括卡车Truck,客车Carriage和小轿车Car,但同一时刻一个位置只能存放0或1辆汽车。
2.管理系统模拟实际车辆停车的情况:新来车辆时如果有空位,按顺序为该车分配停车位;车辆开走时,按停车场的收费标准交纳相应停车费(假定停车场能获取车辆对象的类别);统计各类车辆的数量。
3.定义描述停车场的类Park,其中有n个位置用于存放各类车辆。
4.定义基类Automobile:①驾驶员;②车牌号(字符串)、车辆类别(分为Car、Truck、Carriage);③String
getMobileMessage()车辆相关信息;④parking()泊车、start()开车、pause()暂停等。
5.定义派生类Truck,Carriage和Car,这些车辆除了拥有车牌号(字符串)、车辆已使用年数(整数)之外, Truck还拥有载重量(浮点数,单位吨)属性,Carriage还拥有乘坐人数(整数,单位人)属性,
Car还拥有排气量(浮点数,单位L)属性。
6.每辆车上只有一驾驶员,驾驶员按停车场的收费要求支付费用;按现实停车场的场景来模拟需有的动作(方法):在出口前停车、付费、开车、泊车等。
7.收费标准:其中Truck收费2元/小时,Carriage收费1.5元/小时,Car收费1元/小时。 8.测试上述所要求的各种功能,即根据菜单命令为新来车辆分配停车位、开走车辆(输入车位编号)时付费、显示停车场中各类车辆的数量。
二、程序设计
1.UML图
2.设计思路
①车类设计
无论是Car,Truck还是Carrige,都是继承基类AutoMoblie,它抽象了各种车的公共部分,同时Car,Truck和Carrige都有自己独有的属性,同时基类中有私有属性Type,用来标识车是什么类型的车,同时覆写了getMobileMessage方法(用来返回具体的字符串)
②人与车的关系
车有私有属性people,即AutoMoblie聚合了People类,主要用来模拟人坐进车中这么一个操作;同时People类也依赖于AutoMoblie类,主要体现在调用people方法时,也会相应的调用车的方法。
③停车场类实现方式
停车场内部维护了两个ArrayList数组,一个用来存储车位信息,一个用来存储各车位计时
④停车场自动安排车位和扩容机制
每当车辆进入时,程序会自动检查automobiles,如果有空车位则进入,并且times数组开始计时,否则则对数组进行扩容已达到停车场扩容的效果。
⑤停车场实时情况展示(display方法)
Park类中有个display方法,用于展示当前停车场的具体情况
具体效果如下:
⑥获取总车位信息
Park类中有个获取真实容量的方法,因为Park类中使用ArrayList来存储数据,但是其中真实数组elementData是私有的并不对外提供操作的方法,这时我们获取其真实的容量大小就得通过反射来进行,具体操作如下
⑦类型和收费标准的抽象(Type类和Charging)
为了达到开闭原则,提升系统的延展性,我把类型和收费标准抽象出来单独成类,未来要是要修改类型和收费标准,可以直接替换这两个类,当然更好的操作是再设计接口,未来如果要改,直接实现该接口就行,但是为了方便起见,我这里没有设计相应接口(主要是觉得太麻烦了)。
具体操作如下:
⑧测试类中自定义类MyRandom
为了更好模拟停车场实际情况,特意设计类一个随机类,用于返回随机车牌号等。
⑨测试类模拟停车场
为了使测试更清楚,这里把一秒当做一小时来计算
三、代码详情
1.基类Automobile
package com.dreamchaser.park; public class Automobile { /** * 驾驶员 */ private People people; /** * 车牌号 */ private String number; /** * 车辆已使用年年数 */ private Integer year; /** * 车辆类别 */ private Type type; public People getPeople() { return people; } public void setPeople(People people) { this.people = people; } public Integer getYear() { return year; } public void setYear(Integer year) { this.year = year; } public Type getType() { return type; } public void setType(Type type) { this.type = type; } public Automobile(People people, String number, Integer year) { this.people = people; this.number = number; this.year = year; } public String getMobileMessage(){ return "驾驶员:"+people+" ;车牌号:"+number+" ;车辆类别:"+type; } public void parking(int i){ System.out.println(people+"把车开到"+i+"号车位泊车!"); } public void start(){ System.out.println("车已启动!"); } public void pause(String s){ System.out.println(people+"把车暂时停在了"+s); } }
2.派生类Car
package com.dreamchaser.park; public class Car extends Automobile{ /** * 排气量 */ private float displacement; public Car(People people, String number, Integer year, float displacement) { super(people, number, year); this.displacement = displacement; this.setType(Type.CAR); } @Override public String getMobileMessage() { return super.getMobileMessage()+" ;排气量:"+displacement+"L"; } }
3.派生类Carriage
package com.dreamchaser.park; public class Carriage extends Automobile{ private Integer peopleNumber; public Carriage(People people, String number, Integer year, Integer peopleNumber) { super(people, number, year); this.peopleNumber = peopleNumber; this.setType(Type.CARRIAGE); } @Override public String getMobileMessage() { return super.getMobileMessage()+" ;乘坐人数:"+peopleNumber+"人"; } }
4.派生类Truck
package com.dreamchaser.park; public class Truck extends Automobile{ private float capacity; public Truck(People people, String number, Integer year, float capacity) { super(people, number, year); this.capacity = capacity; this.setType(Type.TRUCK); } @Override public String getMobileMessage() { return super.getMobileMessage()+" ;载重量:"+capacity+"吨"; } }
5.People类
package com.dreamchaser.park; public class People { /** * 驾驶员名字 */ private String name; public People(String name) { this.name = name; } /** * 在出口前停车 */ public void stop(Automobile automobile){ automobile.pause("出口"); } /** * 付费 * @param d */ public void pay(double d){ System.out.println("付费"+d+"元!"); } /** * 开车 */ public void drive(Automobile automobile){ automobile.start(); } /** * 泊车 * @param i */ public void park(Automobile automobile,int i){ automobile.parking(i); } @Override public String toString() { return name; } public void into(Automobile automobile,Park park){ stop(automobile); System.out.println("车辆信息:"+automobile.getMobileMessage()); drive(automobile); park(automobile,park.park(automobile)); System.out.println("---------------------------------------"); } public void out(Automobile automobile,Park park){ drive(automobile); stop(automobile); System.out.println("车辆信息:"+automobile.getMobileMessage()); pay(park.out(automobile)); drive(automobile); System.out.println("---------------------------------------"); } }
6.Park类
package com.dreamchaser.park; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Date; import java.util.List; public class Park { /** *初始停车场车位为10 */ private List<Automobile> automobiles=new ArrayList<>(10); /** * 存储时间 */ private List<Long> times=new ArrayList<>(); int capacity=getArrayListCapacity((ArrayList<?>) automobiles); public int park(Automobile automobile){ Date date=new Date(); int i=0; for (;i<automobiles.size();i++){ Automobile a=automobiles.get(i); if (a==null){ automobiles.set(i,automobile); times.set(i,date.getTime()); return i; } } //车位不够则扩容 automobiles.add(automobile); times.add(date.getTime()); //比较容量,如果size大于容量,说明容量已被扩充,需更新并通知 if (automobiles.size()>capacity){ System.out.println("---------------------------"); capacity=getArrayListCapacity((ArrayList<?>) automobiles); System.out.println("车位扩容!当前停车场车位总数为"+capacity); System.out.println("---------------------------"); } return i; } public double out(Automobile automobile){ Date date=new Date(); long t=0; for (int i=0;i<automobiles.size();i++){ if (automobiles.get(i)==automobile){ automobiles.set(i,null); t=date.getTime()-times.get(i); times.set(i,null); System.out.println(i+"号车位的车已驶离!"); break; } } //这里为了演示清楚,一秒当一小时 return t/1000*Charging.getCharging(automobile.getType()); } /** * 通过反射获取list中的数组,然后通过数组返回其容量大小 * @param arrayList * @return */ public static int getArrayListCapacity(ArrayList<?> arrayList) { Class<ArrayList> arrayListClass = ArrayList.class; try { //获取 elementData 字段 Field field = arrayListClass.getDeclaredField("elementData"); //开始访问权限 field.setAccessible(true); //把示例传入get,获取实例字段elementData的值 Object[] objects = (Object[])field.get(arrayList); //返回当前ArrayList实例的容量值 return objects.length; } catch (Exception e) { e.printStackTrace(); return -1; } } public void display(){ System.out.println("当前停车场情况:"); System.out.println("\t\t\t\t金昊霖的停车场\t\t\t\t"); System.out.println("------------------------------------------------------"); //外置变量记录循环的次数 int a=0; for (Automobile automobile:automobiles){ if (a%5==0){ System.out.println(); System.out.print("|\t"); } if (automobile==null){ System.out.print("空\t|\t"); }else{ System.out.print(a+"\t|\t"); } a++; } System.out.println(); System.out.println("------------------------------------------------------"); } }
7.启动测试类Main
package com.dreamchaser.park; import java.util.ArrayList; import java.util.List; import java.util.Random; public class Main { public static void main(String[] args) { Park park=new Park(); List<People> peoples=new ArrayList<>(20); for (int i=0;i<20;i++){ peoples.add(new People("第"+i+"个志愿者")); } List<Automobile> automobiles=new ArrayList<>(20); for (int i=0;i<20;i++){ Type type=MyRandom.getType(); if (type==Type.CAR){ automobiles.add(new Car(peoples.get(i), MyRandom.getLicense(),MyRandom.getInteger(),MyRandom.getInteger())); }else if (type==Type.CARRIAGE){ automobiles.add(new Carriage(peoples.get(i), MyRandom.getLicense(),MyRandom.getInteger(),MyRandom.getInteger())); }else if (type==Type.TRUCK){ automobiles.add(new Truck(peoples.get(i), MyRandom.getLicense(),MyRandom.getInteger(),MyRandom.getFloat())); } } try { //前十辆驶入停车场 for (int i=0;i<10;i++){ peoples.get(i).into(automobiles.get(i),park); } //显示停车场当前情况 park.display(); //1个小时后 Thread.sleep(1000); //前五辆驶出停车场 for (int i=0;i<5;i++){ peoples.get(i).out(automobiles.get(i),park); } //显示停车场当前情况 park.display(); //后十辆驶入停车场 for (int i=10;i<20;i++){ peoples.get(i).into(automobiles.get(i),park); } //显示停车场当前情况 park.display(); //2个小时后 Thread.sleep(2000); //后十辆驶出停车场 for (int i=10;i<20;i++){ peoples.get(i).out(automobiles.get(i),park); } //显示停车场当前情况 park.display(); //1个小时后 Thread.sleep(1000); //剩下五辆驶出停车场 for (int i=5;i<10;i++){ peoples.get(i).out(automobiles.get(i),park); } //显示停车场当前情况 park.display(); } catch (InterruptedException e) { e.printStackTrace(); } } } class MyRandom{ static Random random=new Random(); public static String getLicense(){ return "浙"+(char) (Math.random ()*26+'A')+(int)(Math.random ()*10)+(int)(Math.random ()*10)+(int)(Math.random ()*10)+(int)(Math.random ()*10); } public static Type getType(){ int i= (int)(Math.random()* Type.values().length); return Type.values()[i]; } public static Integer getInteger(){ return random.nextInt(100); } public static float getFloat(){ return random.nextFloat(); } }
8.Charging类
package com.dreamchaser.park; public class Charging { public static double getCharging(Type type){ if (type==Type.CAR){ return 1; }else if (type==Type.CARRIAGE){ return 1.5; }else{ return 2; } } }
9.Type类
package com.dreamchaser.park; public enum Type { TRUCK,CAR,CARRIAGE }
四、运行结果(测试结果)
注:此处为了更好的模拟效果,程序将一秒当做一小时来计算
总结
此作业涉及继承、覆写、反射、线程、设计模式等Java基础知识点,适合当做初学Java的新手练习。