前言
这是老师带着敲的项目,主要锻炼面向对象思想的实现,针对不同场景应该用什么样的集合容器来存储数据,什么时候该用泛型,什么时候该用分支控制语句,什么时候要避免使用if-else.
进一步理解所谓的通过继承提高程序的扩展性,复用性,以及封装类来保证数据的安全性、一致性,特别是无时无刻都在体现多态
一、实体抽象为对象(🚩)
这是面向对象设计的过程中画出来的分层设计图,把两个实体Movie、User当作两个对象,每一个对象看作一个类来处理,由于系统用户存在商家和客户两类,所以通过继承父类User的形式来实现
定义一个电影类Movie类,Movie类包含:片名、主演、评分、时长、票价、余票系统包含2个用户角色:客户、商家。存在大量相同属性信息
定义User类作为父类,属性:登录名称、密码、真实名称、性别、电话、账户金都定义Business类代表商家角色,属性:店铺名称、地址
定义Customer类代表客户角色,没有额外属性
定义集合List<User>用户存放系统注册的用户对象信息
定义集合Map<Business, List<Movie>>存放商家和其排片信息
==注意==昨天看面试直播中就问到“保存一个人和他的相关信息采用ArrayList、LinkedList还是HashMap”,针对此种场景和本项目,都应该采用Map双列集合来存取,因为Business和Movie对象两者是K-V的映射关系
二、对象封装成类
1.用户User类
这里的loginName目的是用来设置曾用名,在登陆的时候用来和用户输入的userName做对比来实现用户名是否输入正确的目的
public class User {
private String loginName; // 方便以后设置的曾用名
private String userName; // 真名
private String passWord;
private char sex;
private String phone;
private double money;
public User(){
}
public User(String loginName, String userName, String passWord, char sex, String phone, double money) {
this.loginName = loginName;
this.userName = userName;
this.passWord = passWord;
this.sex = sex;
this.phone = phone;
this.money = money;
}
public String getLoginName() {return loginName;}
public void setLoginName(String loginName) {this.loginName = loginName;}
public String getUserName() {return userName;}
public void setUserName(String userName) {this.userName = userName;}
public String getPassWord() {return passWord;}
public void setPassWord(String passWord) {this.passWord = passWord;}
public char getSex() {return sex;}
public void setSex(char sex) {this.sex = sex;}
public String getPhone() {return phone;}
public void setPhone(String phone) {this.phone = phone;}
public double getMoney() {return money;}
public void setMoney(double money) {this.money = money;}
}
2.商户Business类
Business是User类的一个子类,但是他存在私有属性shopName、adress
public class Business extends User{
private String shopName; // 门店名称
private String address; // 门店地址
public String getShopName() {return shopName;}
public void setShopName(String shopName) {this.shopName = shopName;}
public String getAddress() {return address;}
public void setAddress(String address) {this.address = address;}
}
3.顾客Customer类
同时属于User类的子类,这里定义了一个Map类型的buyMovies来存储购买记录
public class Customer extends User{
// 定义一个属性存储购买记录
private Map<String, Boolean> buyMovies = new HashMap<>();
public Map<String, Boolean> getBuyMovies() {return buyMovies;}
public void setBuyMovies(Map<String, Boolean> buyMovies) {this.buyMovies = buyMovies;}
}
4.电影Movie类
在设置电影属性的get、set方法之后我们还要针对电影的评分功能做一个升级,具体是通过List集合把MovieSystem中用户输入的评分转成一个double类型的数据存在其中,然后调用get方法时返回出来
public class Movie {
private String name;
private String actor;
private double time;
private double price;
private int number;
private Date startTime;
public Movie() {}
public Movie(String name, String actor, double time, double price, int number, Date startTime) {
this.name = name;
this.actor = actor;
this.time = time;
this.price = price;
this.number = number;
this.startTime = startTime;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public String getActor() {return actor;}
public void setActor(String actor) {this.actor = actor;}
public double getScore() {
List<Double> scores = MovieSystem.MOVIES_SCORE.get(name);
if(scores!=null && scores.size() > 0){
double sum = 0;
for (Double score : scores) {
sum += score;
}
return BigDecimal.valueOf(sum).divide(BigDecimal.valueOf(scores.size()), 2 , RoundingMode.UP).doubleValue();
}else {
return 0;
}
}
public double getTime() {return time;}
public void setTime(double time) {this.time = time;}
public double getPrice() {return price;}
public void setPrice(double price) {this.price = price;}
public int getNumber() {return number;}
public void setNumber(int number) {this.number = number;}
public Date getStartTime() {return startTime;}
public void setStartTime(Date startTime) {this.startTime = startTime;}
}
三、业务功能实现类
1.设置全局变量
存储用户对象的Listpublic static final List<User> allUserS = new ArrayList<>();
存储商家和电影信息的Mappublic static final Map<Business, List<Movie>>allMovies = new HashMap<>();
处理用户输入的变量public static final Scanner userInfo = new Scanner(System.in);
登陆用户对应的对象public static User loginUser;
时间变量public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
2.首页展示
首页可以通过用户输入的指令,执行相应的业务(登陆、注册)登陆成功会进入后台去买票
private static void showMain() {
while (true) {
System.out.println("===============电影首页=================");
System.out.println("1、用户登录");
System.out.println("2、用户注册");
System.out.println("请输入操作命令:");
String key = userInfo.nextLine();
switch (key) {
case "1":
// 登录
login();
break;
case "2":
//注册
register();
break;
default:
System.out.println("不是内部命令!请重新输入!");
}
}
}
2.1用户登录(🚩)
这里的对登陆的用户是否先前存在的验证方式是:
调用getUserByLoginName()方法,向其形参列表中传入用户名,然后在方法内部遍历一遍存储User对应的List集合并进行比较,如果有就返回这个对象,如果没有就返回null,而反回null导致的结果就是if不成立,登陆失败
当登陆成功,也就是遍历匹配到了对应类型,会返回这个对象user然后继续比较
若是Business类型则会进入商家后台,若是Customer类型则会进入买票后台
private static void login() {
while (true) {
System.out.println("请您输入登录名称:");
String loginName = userInfo.nextLine();
System.out.println("请您输入登录密码:");
String passWord = userInfo.nextLine();
// 1、根据登录名称查询用户对象。
User user = getUserByLoginName(loginName);
// 2、判断用户对象是否存在,存在说明登录名称正确了
if(user != null){
// 3、比对密码是否正确
if(user.getPassWord().equals(passWord)){
// 登录成功了:...
loginUser = user; // 记住登录成功的用户
// 判断是用户登录的,还是商家登录的。
if(user instanceof Customer) {
// 用户登录
showCustomerMain();
}else {
// 商户登录
showBusinessMain();
}
return;
}else {
System.out.println("密码错误!");
}
}else {
System.out.println("登录名称错误!");
}
}
}
验证方法:
遍历集合查找是否存在和曾用名相同的String类型的值
public static User getUserByLoginName(String loginName){
for (User user : allUserS) {
// 判断输入用户名是否存在
if(user.getLoginName().equals(loginName)){
return user;
}
}
return null; // 查询此用户登录名称
}
2.2用户注册
private static void register() {
System.out.println("请注册名称:");
String loginName = userInfo.nextLine();
System.out.println("请设置密码:");
String passWord = userInfo.nextLine();
System.out.println("请设置昵称:");
String userName = userInfo.nextLine();
System.out.println("请设置资产:");
double userMoney = userInfo.nextDouble();
System.out.println("请留下电话:");
String userPhone = userInfo.nextLine();
Customer cus = new Customer();
cus.setLoginName(loginName);
cus.setPassWord(passWord);
cus.setUserName(userName);
cus.setMoney(userMoney);
cus.setPhone(userPhone);
allUserS.add(cus);
}
3.商家后台
比较有意思的是这里用到了三元运算符实现性别输出的判断
private static void showBusinessMain() {
while (true) {
System.out.println("============后台电影界面===================");
System.out.println
(loginUser.getUserName() + (loginUser.getSex()=='男'? "先生":"女士" + "欢迎您进入系统"));
System.out.println("1、展示详情:");
System.out.println("2、上架电影:");
System.out.println("3、下架电影:");
System.out.println("4、修改电影:");
System.out.println("5、退出:");
System.out.println("请输入您要操作的命令:");
String command = userInfo.nextLine();
switch (command){
case "1":
// 展示全部电影
showBusinessInfos();
break;
case "2":
// 上架电影
addMovie();
break;
case "3":
// 下架电影
deleteMovie();
break;
case "4":
// 修改电影
updateMovie();
break;
case "5":
System.out.println(loginUser.getUserName() +"请您下次再来啊~~~");
return;
default:
System.out.println("不是内部命令!!");
break;
}
}
}
3.1展示排片情况
利用Movie类中的get方法得到对应信息
private static void showBusinessInfos() {
System.out.println("================商家详情界面=================");
LOGGER.info(loginUser.getUserName() +"商家,正在看自己的详情~~~");
// 商家对象作为Map集合的键 提取对应的值就是其排片信息
Business business = (Business) loginUser;
System.out.println(business.getShopName() + "\t\t电话:" + business.getPhone()
+ "\t\t地址:" + business.getAddress() + "\t\t余额:" + business.getMoney());
List<Movie> movies = allMovies.get(business);
if(movies.size() > 0) {
System.out.println("片名\t\t\t主演\t\t时长\t\t评分\t\t票价\t\t余票数量\t\t放映时间");
for (Movie movie : movies) {
System.out.println(movie.getName()+"\t\t\t" + movie.getActor()+ "\t\t" + movie.getTime()
+ "\t\t" + movie.getScore() + "\t\t" + movie.getPrice() + "\t\t" + movie.getNumber() + "\t\t"
+ sdf.format(movie.getStartTime()));
}
}else {
System.out.println("您的店铺当前无片在放映~~~~");
}
}
3.2商家上架电影
private static void addMovie() {
System.out.println("================上架电影====================");
Business business = (Business) loginUser;
List<Movie> movies = allMovies.get(business);
System.out.println("请您输入新片名:");
String name = userInfo.nextLine();
System.out.println("请您输入主演:");
String actor = userInfo.nextLine();
System.out.println("请您输入时长:");
String time = userInfo.nextLine();
System.out.println("请您输入票价:");
String price = userInfo.nextLine();
System.out.println("请您输入票数:");
String totalNumber = userInfo.nextLine(); // 200\n
while (true) {
try {
System.out.println("请您输入影片放映时间:");
String stime = userInfo.nextLine();
Movie movie = new Movie(name, actor ,Double.valueOf(time) , Double.valueOf(price)
, Integer.valueOf(totalNumber) , sdf.parse(stime));//封装
movies.add(movie);
System.out.println("上架成功:《" + movie.getName() + "》");
return; // 直接退出去
} catch (ParseException e) {
e.printStackTrace();
}
}
}
3.3商家下架电影
private static void deleteMovie() {
System.out.println("================下架电影====================");
Business business = (Business) loginUser;
List<Movie> movies = allMovies.get(business);
if(movies.size() == 0) {
System.out.println("当期无片可以下架~~");
return;
}
while (true) {
System.out.println("请您输入需要下架的电影名称:");
String movieName = userInfo.nextLine();
// 3、去查询有没有这个影片对象。
Movie movie = getMovieByName(movieName);
if(movie != null){
// 下架它
movies.remove(movie);
System.out.println("您当前店铺已经成功下架了:" + movie.getName());
showBusinessInfos();
return;
}else {
System.out.println("您的店铺没有上架该影片!");
System.out.println("请问继续下架吗?y/n");
String command = userInfo.nextLine();
switch (command) {
case "y":
break;
default:
System.out.println("好的!");
return;
}
}
}
}
3.4修改电影信息
private static void updateMovie() {
System.out.println("================修改电影====================");
Business business = (Business) loginUser;
List<Movie> movies = allMovies.get(business);
if(movies.size() == 0) {
System.out.println("当期无片可以修改~~");
return;
}
4.用户后台
4.1顾客买票(🚩)
private static void buyMovie() {
showAllMovies();
System.out.println("=============用户购票功能=================");
while (true) {
System.out.println("请您输入需要买票的门店名:");
String shopName = userInfo.nextLine();
// 1、查询是否存在该商家。
Business business = getBusinessByShopName(shopName);
if (business == null) {
System.out.println("这家店倒闭啦~");
} else {
// 2、此商家全部的排片
List<Movie> movies = allMovies.get(business);
// 3、判断是否存在上映的电影
if (movies.size() > 0) {
// 4、开始进行选片购买
while (true) {
System.out.println("请您输入需要购买电影名称:");
String movieName = userInfo.nextLine();
// 去当前商家下,查询该电影对象。
Movie movie = getMovieByShopAndName(business, movieName);
if (movie != null) {
// 开始购买
while (true) {
System.out.println("请您输入要购买的电影票数:");
String number = userInfo.nextLine();
int buyNumber = Integer.valueOf(number);
// 判断电影是否购票
if (movie.getNumber() >= buyNumber) {
// 可以购买了
// 当前需要花费的金额
double money = BigDecimal.valueOf(movie.getPrice()).multiply(BigDecimal.valueOf(buyNumber))
.doubleValue();
if (loginUser.getMoney() >= money) {
// 终于可以买票了
System.out.println("您成功购买了" + movie.getName() + buyNumber +
"张票!总金额是:" + money);
// 更新自己的金额 更新商家的金额
loginUser.setMoney(loginUser.getMoney() - money);
business.setMoney(business.getMoney() + money);
movie.setNumber(movie.getNumber() - buyNumber);
Customer c = (Customer) loginUser;
// 记录购买电影的信息
// 第一个参数是购买的电影,第二个参数是没有评价的标记!
c.getBuyMovies().put(movie.getName(), false);
return;
} else {
System.out.println("是否继续~~");
System.out.println("是否继续买票?y/n");
String command = userInfo.nextLine();
switch (command) {
case "y":
break;
default:
System.out.println("好的!");
return;
}
}
} else {
// 票数不够
System.out.println("您当前最多可以购买:" + movie.getNumber());
System.out.println("是否继续买票?y/n");
String command = userInfo.nextLine();
switch (command) {
case "y":
break;
default:
System.out.println("OK");
return;
}
}
}
} else {
System.out.println("查无此片");
}
}
} else {
System.out.println("该电影院关门了~~~");
System.out.println("是否继续买票?y/n");
String command = userInfo.nextLine();
switch (command) {
case "y":
break;
default:
System.out.println("OK");
return;
}
}
}
}
}
4.2查看排片
private static void showAllMovies() {
System.out.println("=============展示全部商家排片信息=================");
allMovies.forEach((business, movies) -> {
System.out.println(business.getShopName() + "\t\t电话:" + business.getPhone() + "\t\t地址:" + business.getAddress());
System.out.println("\t\t\t片名\t\t\t主演\t\t时长\t\t评分\t\t票价\t\t余票数量\t\t放映时间");
for (Movie movie : movies) {
System.out.println("\t\t\t" + movie.getName()+"\t\t\t" + movie.getActor()+ "\t\t" + movie.getTime()
+ "\t\t" + movie.getScore() + "\t\t" + movie.getPrice() + "\t\t" + movie.getNumber() + "\t\t"
+ sdf.format(movie.getStartTime()));
}
});
}
跟着写完突然开始怀疑人生,说实话我觉得用API很简单,难的是根据不同业务场景来用代码实现逻辑