城堡游戏

一、城堡游戏介绍:
1.这个程序的任务是通过玩家的输入的方向(纯文字)在虚构的城堡内移动(以纯文字作为移动后的返回结果)。
2.这个程序接受help、bye、go south、go north、go west、go east六种命令,要求命令单独一行输入并在结束时敲回车,另外如果接受go xxx的不合规信息会输出不存在这样的房间。
3.help提供帮助信息,bye结束游戏,go后面空一格加south、north、west、east表示在虚构的城堡中移动。
4.有五个地点,分别是:小酒吧,大厅,书房,卧室,次卧。
5.地图:

二、类的设计
首先我们要有三个类,第一个是Game类,用来表示游戏本身和执行各种游戏命令,第二个是Room类,用来表示游戏中的所有房间。可见整个城堡游戏只由这两个类构成,具体怎么运行就要先构造这两个大类。

1.Game类
Game类是整个游戏运行的核心,具有构造房间,开始游戏,执行命令三个功能。

2.Room类
城堡游戏中是由很多个小房间构成的,分别是小酒吧,大堂,书房,卧室,次卧这五个地点。每个房间只有一种属性,即description(房间名)。

三、具体实现
1.类的创建
首先我们要创造一个Game类,用来作为游戏的主体。我们知道Game类有三个功能,构造房间,开始游戏,执行命令。那么在

实现:

package jinjie_01;

import java.util.Scanner;

public class Game {
private Room currentRoom; public Game()
{
createRooms();
} private void createRooms(){
Room pub,lobby,study,bedroom,bedroom1;
//创造房间
pub = new Room("小酒馆");
lobby = new Room("大厅");
study = new Room("书房");
bedroom = new Room("卧室");
bedroom1 = new Room("次卧");
//设置出口
pub.setExits(null,null,null,lobby);
lobby.setExits(null,study,pub,bedroom1);
study.setExits(lobby,null,null,bedroom);
bedroom.setExits(null,null,study,null);
bedroom1.setExits(null,null,lobby,null); currentRoom = pub;
} public void printWelcome(){
System.out.println("***********************************");
System.out.println("欢迎来到城堡游戏!");
System.out.println("这是一个超级无聊的小游戏。");
System.out.println("如果需要帮助,请输入help。");
System.out.println("那么我们开始游戏吧!");
System.out.println("***********************************");
System.out.println("现在你在"+currentRoom);
} private void printHelp()
{
System.out.println("迷路了吗?你可以做的命令有:go | bye | help");
System.out.println("如:\tgo east");
} private void goRoom(String direction) {
Room nextRoom = null;
if (direction.equals("north")) {
nextRoom = currentRoom.northExit;
}
if (direction.equals("east")) {
nextRoom = currentRoom.eastExit;
}
if (direction.equals("south")) {
nextRoom = currentRoom.southExit;
}
if (direction.equals("west")) {
nextRoom = currentRoom.westExit;
}
if(nextRoom == null){
System.out.println("那里没有门!");
}
else{
currentRoom = nextRoom;
System.out.println("你在"+ currentRoom);
System.out.println("出口有:");
if(currentRoom.northExit != null)
System.out.println("north");
if(currentRoom.eastExit != null)
System.out.println("east");
if(currentRoom.southExit != null)
System.out.println("south");
if(currentRoom.westExit != null)
System.out.println("west");
}
} public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Game game = new Game();
game.printWelcome();
while (true) {
String line = in.nextLine();
String[] words = line.split(" ");
if (words[0].equals("help")) {
game.printHelp();
}
else if ( words[0].equals("go")) {
game.goRoom(words[1]);
}
else if ( words[0].equals("bye")){
break;
}
}
System.out.println("***********************************");
System.out.println("游戏到此结束!");
System.out.println("欢迎下次光临!");
System.out.println("谢谢!");
System.out.println("***********************************");
}
}

消除代码复制

首先,会发现下面这段代码在Game类中出现了两次,无疑这会使代码看起来并不优雅,重要的是:在程序中存在相似甚至相同的代码块,是非常低级的代码质量问题。

System.out.println("现在你在" + currentRoom);
System.out.print("出口有:");
if(currentRoom.northExit != null)
System.out.print("north ");
if(currentRoom.eastExit != null)
System.out.print("east ");
if(currentRoom.southExit != null)
System.out.print("south ");
if(currentRoom.westExit != null)
System.out.print("west ");

代码复制存在的问题是,如果需要修改一个副本,那么就必须同时修改所有其他的副本,否则就 存在不一致的问题。这增加了维护程序员的工作量,而且存在造成错误的潜在危险。很可能发 生的一种情况是,维护程序员看到一个副本被修改好了,就以为所有要修改的地方都已经改好 了。因为没有任何明显迹象可以表明另外还有一份一样的副本代码存在,所以很可能会遗漏还 没被修改的地方。
我们从消除代码复制开始。消除代码复制的两个基本手段,就是函数和父类。
这里用函数来解决城堡游戏中重复代码的问题:

public void showPrompt() {
System.out.println("现在你在" + currentRoom);
System.out.print("出口有:");
if(currentRoom.northExit != null)
System.out.print("north ");
if(currentRoom.eastExit != null)
System.out.print("east ");
if(currentRoom.southExit != null)
System.out.print("south ");
if(currentRoom.westExit != null)
System.out.print("west ");
}

删除重复的代码,在重复的地方调用showPrompt() 函数即可。

Java 进阶P-5.1+P-5.2的更多相关文章

  1. Java 进阶 hello world! - 中级程序员之路

    Java 进阶 hello world! - 中级程序员之路 Java是一种跨平台的语言,号称:"一次编写,到处运行",在世界编程语言排行榜中稳居第二名(TIOBE index). ...

  2. Java进阶(五)Java I/O模型从BIO到NIO和Reactor模式

    原创文章,同步发自作者个人博客,http://www.jasongj.com/java/nio_reactor/ Java I/O模型 同步 vs. 异步 同步I/O 每个请求必须逐个地被处理,一个请 ...

  3. Java线程间通信方式剖析——Java进阶(四)

    原创文章,同步发自作者个人博客,转载请在文章开头处以超链接注明出处 http://www.jasongj.com/java/thread_communication/ CountDownLatch C ...

  4. Java进阶(三)多线程开发关键技术

    原创文章,同步发自作者个人博客,转载请务必以超链接形式在文章开头处注明出处http://www.jasongj.com/java/multi_thread/. sleep和wait到底什么区别 其实这 ...

  5. 当我们说线程安全时,到底在说什么——Java进阶系列(二)

    原创文章,同步发自作者个人博客,转载请以超链接形式在文章开头处注明出处http://www.jasongj.com/java/thread_safe/ 多线程编程中的三个核心概念 原子性 这一点,跟数 ...

  6. Java进阶03 IO基础

    链接地址:http://www.cnblogs.com/vamei/archive/2013/04/11/3000905.html 作者:Vamei 出处:http://www.cnblogs.com ...

  7. Java进阶01 String类

    链接地址:http://www.cnblogs.com/vamei/archive/2013/04/08/3000914.html 作者:Vamei 出处:http://www.cnblogs.com ...

  8. 从ConcurrentHashMap的演进看Java多线程核心技术 Java进阶(六)

    本文分析了HashMap的实现原理,以及resize可能引起死循环和Fast-fail等线程不安全行为.同时结合源码从数据结构,寻址方式,同步方式,计算size等角度分析了JDK 1.7和JDK 1. ...

  9. Java进阶(七)正确理解Thread Local的原理与适用场景

    原创文章,始自发作者个人博客,转载请务必将下面这段话置于文章开头处(保留超链接). 本文转发自技术世界,原文链接 http://www.jasongj.com/java/threadlocal/ Th ...

  10. Java进阶(四十七)Socket通信

    Java进阶(四十七)Socket通信   今天讲解一个 Hello Word 级别的 Java Socket 通信的例子.具体通讯过程如下: 先启动Server端,进入一个死循环以便一直监听某端口是 ...

随机推荐

  1. centos7离线安装PHP7

    环境 centos7.9 PHP7.4.30 准备工作 在编译PHP时会提示一些包版本不够或者缺少某些包,一般选择yum来安装缺少的包,但因为是离线安装,所以可以手动配置本地yum源.先看一下系统版本 ...

  2. onps栈使用说明(1)——API接口手册

    1. 底层API 由协议栈底层提供的api,用于涉及底层操作的一些功能实现,这些api接口函数的原型定义分布于不同的文件,它们被统一include进了onps.h中: open_npstack_loa ...

  3. 成熟企业级开源监控解决方案Zabbix6.2关键功能实战-下

    @ 目录 实战 Zabbix server源码安装使用示例 部署 配置 Zabbix agent2使用示例 部署 配置 Zabbix proxy使用示例 部署 配置 自定义监控使用示例 触发器使用示例 ...

  4. zabbix-钉钉报警部署

    zabbix-钉钉报警部署 1. 流程说明 申请钉钉机器人 获取Webhook配置安全设置 获取钉钉号 使用脚本(shell/python)调用钉钉接口: python 输入收件人 信息 配置发件人 ...

  5. SpringCloud——Eureka Feign Ribbon Hystrix Zuul等关键组件的学习与记录

    SpringCloud--Eureka Feign Ribbon Hystrix Zuul等关键组件的学习与记录 前言:本篇是对近日学习狂神SpringCloud教程之后的感想和总结,鉴于对Sprin ...

  6. 【RPC和Protobuf】之RPC入门

    一,概念 RPC:Remote procedure call(远程过程调用),分布式系统中不同节点之间流行的通信方式 服务端: 注: 1.执行下面的代码之后,会相应的启动一个tcp进程 C:\User ...

  7. (GCC) gcc 编译选项 -fno-omit-frame-pointer,-fno-tree-vectorize,fno-optimize-sibling-calls;及内存泄漏、非法访问检测 ASAN

    omit-frame-pointer 开启该选项,主要是用于去掉所有函数SFP(Stack Frame Pointer)的,即在函数调用时不保存栈帧指针SFP,代价是不能通过backtrace进行调试 ...

  8. 使用repo上传代码

    前言~ repo是一款安卓用于管理源码的工具,由python实现,基于git工具 本文介绍了repo的常用使用方式. 一,下载代码 1. repo init 初始化命令 此命令常用选项就那几个,此处取 ...

  9. 基于.NetCore开发博客项目 StarBlog - (20) 图片显示优化

    前言 我的服务器带宽比较高,博客部署在上面访问的时候几乎没感觉有加载延迟,就没做图片这块的优化,不过最近有小伙伴说博客的图片加载比较慢,那就来把图片优化完善一下吧~ 目前有两个地方需要完善 图片瀑布流 ...

  10. 【Impala】概念、原理、内外部shell、建库建表、分区、查询、自定义函数、存储压缩

    一.基本概念 1.介绍 对HDFS.Hbase数据的高性能.低延迟的交互式SQL查询功能 2.优缺点 优点:基于内存运算,无需写入磁盘,无需转化为MR,支持Data Locality调度(数据和计算在 ...