实现赛博朋克宠物商店
你是宇宙中,最有名的一家 Cyberpunk 宠物商店的老板,而你的雇员全是你所发明的机器人,他们是——商店总管李、宠物看护者、宠物 Tony 哥、宠物饲喂猿、宠物服装师、宠物驯化王……,你的顾客来着宇宙的每一个角落。
显然你的宠物店规模和业务量都很大,为了摸索更正当的经营形式,你打算通过软件模仿你的商店,在未来(当初不必做)通过剖析商店日志找到优化计划。
商店总管李:负责与客户交换,帮忙客户抉择相应的服务,并安顿其余机器人执行相应我的项目。服从你的指令,汇报宠物店在某段时间产生了什么。
宠物看护者:负责宠物的寄养,宠物客人将宠物交给商店,寄养,设定寄养工夫,到时告诉认领(与上次不同,这次要实现真正的计时,并且实现真正到时揭示,能够用程序中的一秒模仿事实世界中的一小时(或十分钟))。
宠物 Tony 哥:负责给宠物的毛发洗、剪、吹、拉、烫、染、焗,这里使用装璜者模式,实现对宠物毛发的装璜。
宠物饲喂猿:负责给宠物喂食,当宠物饿的时候(过了一段时间就会饿)。
宠物服装师:负责给宠物穿各种各样的服饰,色彩能够是红、橙、黄、绿、青、蓝、紫(也不肯定都要),品种能够是帽、鞋、裤、褂、裙,材质能够是棉、麻、丝、绒、革;同 Tony 哥一样,负责对宠物衣着装璜,应用装璜者模式。
为了商店收益最大化,每一类的机器人你都发明了很多很多个(总是够用),但总管李只有一个,当总管李服务了顾客抉择了相应的生产我的项目,相应的我的项目立马转到后盾执行,这样总管李又能够马上服务新的客人。每一项我的项目都有规范的执行流程,因而每个同类我的项目(例如,所有宠物染色的工夫,戴帽的工夫)执行的工夫能够看作是雷同的,不同类我的项目执行工夫不同。为了分明商店的运行状况,你要求每个机器人把本人的每一步操作写到商店日志里,当然这也是私下进行的。
你总是很忙,忙着创造新的机器人,没有工夫看商店日志,因而,你能够要求总管李汇报商店在某一段时间产生了哪些事。
思路剖析
利用 单例模式 建设 Manager 类接管顾客服务信息,在 CyberpunkPetShop 类内实例化 Manager 并建设两个线程,利用 线程通信 实现有限次顾客进入,线程种利用 state 决定与判断是否不再接管新的顾客并终止线程,Manager 类内的 run 办法利用接管到的宠物和服务信息实例化 Pet 类,并开启 Pet 服务线程,在 Pet 类内定义了几个服务入口,一个是蕴含了看护和喂食的办法 Mind(),一个是实现发型设计的 designHair 办法,还有一个是实现服装设计的 designCostume 办法。通过实例化 Pet 类并开启办法实现宠物服务。其中继承抽象类 Hair 的未装璜类为 SimpleHair 类, 装璜器类为 HairDecorator,HairDecorator 有 PermHair,PullHair 等具体实现,继承抽象类 Costume 类的未装璜类有 Skirt,Pant 等,装璜器类为CostumeColor,CostumeColor 有对应 Black,Brown 等具体实现。这里利用装璜器模式能够实现繁难的服装和发型搭配。程序运行过程中因为是多线程运行,所以采纳了 日志框架 log4j进行商店服务过程信息的记录。程序在不再接管新的顾客之后对日志进行一次输入。残缺日志能够在对应 info.log 中查看。
程序框架:
几个次要的类:
接管顾客服务要求的 Manager 类:
要害:单例模式中的饿汉式,线程通信
package com.CyberpunkPetShop.java;
import org.apache.log4j.Logger;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
// 主管李类,负责解决顾客需要
public class ManagerLi implements Runnable {
// 单例模式创立主管李
private boolean state;// 标记是否不再接管新的顾客
private int signal;// 不再接管新的顾客时收回的信号标记
private int customerNum;// 顾客编号
private static Logger logger = Logger.getLogger(ManagerLi.class);
private static ManagerLi managerLi = new ManagerLi();// 只有 static 的成员能力在没有创建对象时进行初始化
private ManagerLi(){
state = true;
customerNum = 1;
}
public static ManagerLi getInstance() {return managerLi;}
public static void showShopLog(){
try {BufferedReader br = new BufferedReader(new FileReader("info.log"));
String s;
while((s = br.readLine()) != null){System.out.println(s);
}
} catch (FileNotFoundException e) {logger.error(e.getMessage());
} catch (IOException e) {logger.error(e.getMessage());
}
}
@Override
public void run() {while(true){synchronized (managerLi) {notify();
if(state) {System.out.println("欢送" + customerNum + "号顾客来到赛博朋克宠物店!我是总管李!上面将由我为你安顿服务!");
logger.info("第" + customerNum + "位顾客进入商店");
customerNum++;
System.out.println("请输出你的宠物的名称:");
Scanner scan = new Scanner(System.in);
String p = scan.next();
scan.nextLine();
Pet pet = new Pet();
pet.setName(p);
System.out.println("这是服务菜单:\n1. 寄养宠物 \n2. 为宠物装扮头发 \n3. 为宠物装璜衣服 \n0. 抉择服务结束 \n 请进行抉择:(每个服务以换行离开)");
boolean[] c = new boolean[4];// 服务抉择
boolean[] h = new boolean[5];// 头发装璜抉择
boolean[] w_t = new boolean[5];// 服装类型抉择
boolean[] w_c = new boolean[5];// 服装色彩抉择
while (true) {int choice = new Scanner(System.in).nextInt();
if (choice == 0) break;
c[choice] = true;
}
// 若顾客想要理发
if(c[2]) {h[0] = true;
System.out.println("输出 1 进行装璜头发抉择,输出其余只进行简略理发");
var ch = new Scanner(System.in).next();
if (ch.equals("1")) {System.out.println("装璜头发服务菜单:\n1. 染发 \n2. 烫发 \n3. 洗发 \n4. 拉发");
int ch1 = new Scanner(System.in).nextInt();
h[ch1] = true;
}
}
// 若顾客想要装璜服装
if(c[3]){System.out.println("进行服装类型抉择:\n1. 帽子 \n2. 裤子 \n3. 裙子 \n4. 毛衣");
Scanner in = new Scanner((System.in));
int ch;
ch = in.nextInt();
w_t[ch] = true;
System.out.println("进行服装色彩抉择:\n1. 红色 \n2. 黄色 \n3. 彩色 \n4. 棕色");
ch = in.nextInt();
w_c[ch] = true;
}
pet.setService(c);
pet.setHairService(h);
pet.setCostumeTypeService(w_t);
pet.setCostumeColorService(w_c);
Thread t = new Thread(pet);
t.setName(pet.getName() + "服务线程");
t.start();
try {wait();
if(state) {System.out.println("输出 1 持续接收顾客,输出 0 不再接收顾客:");
int choose = new Scanner(System.in).nextInt();
if (choose == 0) state = false;
}
} catch (InterruptedException e) {logger.error(e.getMessage());
}
}else{
signal++;
if(signal == 1) {System.out.println("本店明天不再接收新的顾客!");
System.out.println("期待残余服务完结......");
logger.info("赛博朋克商店明天不再接收新的顾客");
}
break;
}
}
}
}
}
装璜器类 CostumeColor 类及 HairDecorator
利用装璜器模式进行繁难的搭配设计
package com.Costume.java;
// 服装色彩装璜类,利用装璜器模式设计头发
public class CostumeColor extends Costume{
private Costume costume;
public CostumeColor(Costume obj){this.costume = obj;}
@Override
public String getDepression() {return depression + costume.getDepression();
}
}
package com.Hair.java;
// 头发装璜类,利用装璜器模式设计发型
public class HairDecorator extends Hair{
private Hair hair;
public HairDecorator(Hair obj){this.hair = obj;}
public String getDepression(){return depression + "+" + hair.depression;}
}
日志信息配置:
### 设置 ###
log4j.rootLogger = INFO, A, B
### 输入 INFO 级别以上的日志到 =D://@java/ForthComputerPractice/info.log ###
log4j.appender.A = org.apache.log4j.FileAppender
log4j.appender.A.File = D://@java/ForthComputerPractice/info.log
log4j.appender.A.Append = false
log4j.appender.A.Threshold = INFO
log4j.appender.A.layout = org.apache.log4j.PatternLayout
log4j.appender.A.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%t:%r] - [%p] %m%n
### 输入 WARN 级别以上的日志到 =D:/@java/ForthComputerPractice/error.log ###
log4j.appender.B = org.apache.log4j.FileAppender
log4j.appender.B.File =D://@java/ForthComputerPractice/error.log
log4j.appender.B.Append = false
log4j.appender.B.Threshold = ERROR
log4j.appender.B.layout = org.apache.log4j.PatternLayout
log4j.appender.B.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%t:%r] - [%p] %m%n
须要残缺源码可在 github 或者 gitee 进行 clone:
https://gitee.com/jiang-zhihang/cyberpunk-pet-shop.git
https://github.com/akynazh/CyberpunkPetShop.git
后续发现有问题会继续进行版本更新。