首页 > 其他分享 >软件实训总结

软件实训总结

时间:2023-02-24 21:13:18浏览次数:47  
标签:总结 return String 房间 Game command 实训 软件 public

实践任务1:代码规范与标注

目标

1. 阅读和理解样例代码

  • fork样例工程,并clone到本地仓库;
  • 在本地开发环境上运行样例工程,理解样例工程的代码逻辑;
  • 精读样例工程软件代码,描述代码结构及部件组成;
  • 以UML图描述样例工程的组成及结构图(类及类之间的关系);

2. 标注样例工程中的代码

  • 基于javadoc规范标注代码,对包、类、方法、代码片段、参数和语句等代码层次进行注释(可参考Game类的标注样例);
  • 注释后的代码提交到本地代码库后,同步推送到远程代码仓库;
  • 可参考ESLint、github/super-linter等开发插件了解关于代码规范的相关知识;

3. 扩充和维护样例工程

  • 对样例代码中的功能设计进行分析,找出若干设计缺陷和改进点,并进行修正或扩充,并集成到工程代码中;
  • 可借助代码质量分析工具或代码规范检查工具(如SonarQube、ESLint等)对代码质量进行分析,发现潜在问题;

4. 任务输出

  • 以UML图表示的样例工程软件结构;
  • 在所有源代码文件中完成源代码标注和扩充,并通过git提交到代码库;
  • 在项目根目录下创建一个名称为REPORT.md的文件(与README.md文件同级),以markdown语法格式编写本实训任务的报告,主要包含样例工程的代码结构分析(可以用UML类图及文字进行说明),以及自己改进的功能实现说明;

1. 阅读和理解样例代码

通过Git 工具将项目 fork 到本地,打开IDEA加载此项目,在加载过程中需要配置运行项目的JDK等环境。

此项目采用JDK1.8 版本编译执行。

1.1 项目结构

在这里插入图片描述

项目整体可以看成是一种C/S架构,区分为客户端和服务器,由用户启动游戏后在终端输入一些命令。这些命令被服务器所接收识别 ,逐步经过命令接收、命令识别、命令解析、执行命令四个步骤,然后将结果反馈给用户。

1.2 系统用例图

在这里插入图片描述

当前项目主要的实现目标就是玩家能够输入 Help、Go、Quit指令来操纵游戏,因此从用户角度来考虑系统用例就是玩家进入游戏输入命令。在系统内部包含对用户输入指令的识别、解析、然后执行,最后根据指令的类型确定是否有结果反馈。

1.3 系统类图

在这里插入图片描述

1.3.1 类功能分析

整个项目主要由以下五个类构成:

  • Command :用来接收用户输入的指令,内部包含基础指令(commandWord)、具体指令(secondWord);
  • CommandWords :系统内部可用指令,主要是三个指令 Quit、Go、Help;
  • Room :系统中所有房间的基类,主要包含两个属性 description(房间名称)、exits(房间出口与其它房间的关系);后续可以实现继承该类来构建不同的房间对象。
  • Parser :解析终端用户输入命令的工具类。和CommandWords类是组合关系。内部主要通过Scanner对象获取用户输入,然后对输入的命令进行解析,解析成两个单词,前一个单词必须是系统内部可用指令之一,后一个单词表示具体的命令。比如说房间移动命令 go east,就表示启用 go 命令,然后向东方向移动。
  • Game :游戏的主类,用户进入游戏后项目就执行此类的 play() 方法开始执行游戏。在初始化 Game类对象时执行 createRooms()方法来初始化房间,同时初始化加载 Parser工具类对象来执行命令解析的操作。

1.3.2 类间关系分析

Main

public class Main {

    public static void main(String[] args) {
        Game game = new Game();
        game.play();
    }
}

主启动类,通过 new 生成了一个 Game 类的对象,然后调用它的 play() 方法开始游戏。

主启动类的功能实现需要 Game类的协助,Game类表现为 Main中的局部变量,因此二者是依赖关系。

Game

public class Game
{
    private Parser parser;
    private Room currentRoom;

    private void createRooms(){Room outside, theater, pub, lab, office;}
    public void play()
    {
        printWelcome();

        // Enter the main command loop.  Here we repeatedly read commands and
        // execute them until the game is over.

        boolean finished = false;
        while (! finished) {
            // 获取解析后的命令
            Command command = parser.getCommand();
            // 边执行命令边获取结果(可退出)
            finished = processCommand(command);
        }
        System.out.println("Thank you for playing.  Good bye.");
    }
    private boolean quit(Command command)
    {
        if(command.hasSecondWord()) {
            System.out.println("Quit what?");
            return false;
        }
        else {
            return true;  // signal that we want to quit
        }
    }
}

Game类中有两个成员变量,分别是 Parser类和 Room类,因此GameParserRoom之间是一种组合关系。

Game类的方法quit(Command command)Command 类对象作为方法参数出现,因此二者之间是依赖关系。

Parser

public class Parser
{
    private CommandWords commands;  // 所有有效命令集合
    private Scanner reader;         // Scanner输入对象

    public Command getCommand()
    {
        String inputLine;   // will hold the full input line
        String word1 = null;
        String word2 = null;
        if(commands.isCommand(word1)) {
            return new Command(word1, word2);
        }
    }
}

Parser类中有CommandWords类对象作为成员变量,因此二者之间是组合关系;

Parser类的方法getCommand()中有Command类作为方法的局部变量,因此二者之间是依赖关系。

2. 标注样例工程中的代码

具体的工程注解已经通过Git同步到GitHub上,可前往查看。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. 扩充和维护样例工程

3.1 优化点一、Room类与Game类耦合度高

问题发现

通过类图我们可以发现 Room类和Game类之间是组合关系,二者的耦合度非常高。但是游戏中肯定不止一个房间,假设存在RoomARoomBRoomC三个房间类,这样就会造成这些房间类和Game类之间的强耦合,那么当我们需要修改某一个房间类时就会牵扯到Game类的相关代码改动,这样每次都需要进行很繁杂的维护,这里就存在问题。

解决策略1:(依赖倒置原则+工厂方法设计模式)

思想:

按照设计模式六大原则中的依赖倒置原则。

  1. 上层不应该依赖于下层的实体类,两者都应该依赖于抽象或者接口,实现面向接口编程。

  2. 抽象不应该依赖于细节(具体实现类)。

  3. 细节(具体实现类)应该依赖于抽象。

那么我们就可以将Room 类构造成一个抽象类,然后Game类依赖于抽象类Room,通过构造函数或者setter()方法来传递依赖对象。

同时在创建不同类型的房间时我们不需要知道房间内部的创建细节,只需要得到这个房间对象就可以了,因此还可以结合工厂方法模式来搭建房间工厂生成房间对象,这样做的好处就是当我们每次需要生成一个新房间时只需要新增该房间对应的生产工厂,在工厂内部定义如何生产房间,其它代码都不需要修改,这样极大程度上降低了程序代码的耦合度,代码维护起来更方便。

代码:

在这里插入图片描述

新加入了一个room包,该包中主要放置生产房间的工厂和房间基类。

更详细代码可查看 Github

AbsRoom

/**
 * 抽象房间类
 */
public abstract class AbsRoom {
    private String description;
    private HashMap<String, AbsRoom> exits;

    public void setDescription(String name){
        this.description = name;
    }

    public void setExit(String direction, AbsRoom neighbor)
    {
        exits.put(direction, neighbor);
    }

    public String getShortDescription()
    {
        return description;
    }

    public String getLongDescription()
    {
        return "You are " + description + ".\n" + getExitString();
    }

    private String getExitString()
    {
        String returnString = "Exits:";
        Set<String> keys = exits.keySet();
        for(String exit : keys) {
            returnString += " " + exit;
        }
        return returnString;
    }

    public AbsRoom getExit(String direction)
    {
        return exits.get(direction);
    }
}

SchoolBuilder

public class SchoolBuilder implements RoomBuilderFactory{

    @Override
    public AbsRoom createRoom() {
        int number = 401;
        int floor = 3;
        HashMap<String,Object> objects = new HashMap<>();
        objects.put("desk",40);
        objects.put("computer",1);
        objects.put("fan",6);
        objects.put("airConditioning",2);
        return new SchoolRoom(number,floor,objects);
    }
}
结果对比:

在这里插入图片描述

解决策略2:引入Spring框架

对于耦合性高的问题,更加简单高效的方法是采用Spring框架,对象的管理权不由使用对象的双方来控制管理,而由与对象无关的Spring 容器来管理,SpringIOC思想(控制反转),就是降低耦合度的非常棒的选择。

而且引入Spring框架后还可以使用AOP的功能对项目中的某些代码进行增强,它使用了动态代理的原理实现了对某些方法的进一步强化,而不用去修改其它模块的代码。比如说玩家探险时可以在某个固定的时刻进行消息提示、对于一些禁止操作也可以进行记录。

这里由于时间有限就不附上代码了,想要学习了解可以参考我的Github

https://github.com/iStitches/Spring_IOC_Conclusion

3.2 优化点二、策略模式使用

问题发现

针对Game类的如下代码可进行相关的优化操作:

    private boolean processCommand(Command command)
    {
        boolean wantToQuit = false;

        // 无效命令
        if(command.isUnknown()) {
            System.out.println("I don't know what you mean...");
            return false;
        }

        // 获取命令字段1
        String commandWord = command.getCommandWord();
        if (commandWord.equals("help")) {
            printHelp();
        }
        else if (commandWord.equals("go")) {
            goRoom(command);
        }
        else if (commandWord.equals("quit")) {
            wantToQuit = quit(command);
        }
        // else command not recognised.
        return wantToQuit;
    }

可以发现代码中存在多个 if-else语句,那么当项目中再增加多个有效指令时就会产生许多if-else,不仅代码不美观而且性能、安全性都比较差。

解决策略:采用策略模式调整代码结构

思想:

可以采取策略模式来减少代码中的if-else语句,实现算法和具体上下文的分离。策略模式需要定义一个上下文对象Context、抽象的策略角色Strategy、具体的策略角色ConcreteStrategy

代码:

在这里插入图片描述

上下文Context

/**
 * 策略模式-------上下文类
 */
public class Context {
    private Strategy strategy;

    public Context(Strategy strategy){
        this.strategy = strategy;
    }

    public Object getResult(){
        return strategy.copeWithCommand();
    }
}

抽象策略角色 Strategy

public abstract class Strategy {
    private Command command = null;
    private Game game = null;

    public Command getCommand(){
        return this.command;
    }

    public Game getGame(){
        return this.game;
    }

    public Strategy(Command command,Game game) {
        this.command = command;
        this.game = game;
    }

    public abstract Object copeWithCommand();
}

具体策略对象 StrategyGo

public class StrategyGo extends Strategy{

    private Command command = getCommand();
    private Game game = getGame();

    public StrategyGo(Command command, Game game) {
        super(command,game);
    }

    @Override
    public Object copeWithCommand() {
        if(!command.hasSecondWord()) {
            // if there is no second word, we don't know where to go...
            System.out.println("Go where?");
            return "Unknow where to Go....";
        }

        String direction = command.getSecondWord();

        // 尝试离开当前房间,前往新房间
        AbsRoom nextRoom = game.getCurrentRoom().getExit(direction);

        if (nextRoom == null) {
            System.out.println("There is no door!");
        }
        // 切换房间
        else {
            game.setCurrentRoom(nextRoom);
            System.out.println(game.getCurrentRoom().getLongDescription());
        }
        return "Success moving !";
    }

具体策略对象 StrategyHelp

public class StrategyHelp extends Strategy{
    private Game game = null;

    public StrategyHelp(Command command, Game game) {
        super(command,game);
    }

    @Override
    public Object copeWithCommand() {
        System.out.println("You are lost. You are alone. You wander");
        System.out.println("around at the university.");
        System.out.println();
        System.out.println("Your command words are:");
        game.getParser().showCommands();
        return null;
    }
}

具体策略对象 StrategyQuit

public class StrategyQuit extends Strategy{
    public StrategyQuit(Command command, Game game) {
        super(command,game);
    }

    @Override
    public Object copeWithCommand() {
        Command command = getCommand();
        if(command.hasSecondWord()) {
            System.out.println("Quit what?");
            return false;
        }
        else {
            return true;  // signal that we want to quit
        }
    }
}
结果对比:

在这里插入图片描述

4. 利用Javadoc检查代码规范

通过在IDEA中进行相关的配置,导出代码注释的规范性检查文件

Javadoc工具的使用:

https://monday.blog.csdn.net/article/details/80296136?utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromMachineLearnPai2~default-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromMachineLearnPai2~default-1.control

https://www.cnblogs.com/xiaoming0601/p/6657136.html

注释样例

/**
 * 该类是项目中所有房间的基类
 * 包含两个属性:  description(房间名称)、exits(房间出口与其它房间的关系)
 * @author  Michael Kölling and David J. Barnes
 * @version 1.0
 */
public class Room
{
    private String description;             //房间名
    private HashMap<String, Room> exits;    //与其它房间的关系

    public Room(String description)
    {
        this.description = description;
        exits = new HashMap<>();
    }

    /**
     * 设置当前房间与其它相邻房间的关系
     * @param direction 目标Room所指向的方向描述
     * @param neighbor 相邻方向的房间对象
     */
    public void setExit(String direction, Room neighbor)
    {
        exits.put(direction, neighbor);
    }

    /**
     *  简要描述当前位置
      * @return 返回房间的简要描述
     */
    public String getShortDescription()
    {
        return description;
    }

    /**
     * 详细描述当前位置
     * @return String 返回房间的详细描述
     */
    public String getLongDescription()
    {
        return "You are " + description + ".\n" + getExitString();
    }

    /**
     * 展示所有和当前房间相邻的房间信息
     * @return String 相邻房间的信息
     */
    private String getExitString()
    {
        String returnString = "Exits:";
        Set<String> keys = exits.keySet();
        for(String exit : keys) {
            returnString += " " + exit;
        }
        return returnString;
    }

    /**
     * 获取指定方向的房间信息
     * @param direction 所描述的方向
     * @return Room 对应方向的房间对象
     */
    public Room getExit(String direction)
    {
        return exits.get(direction);
    }
}

命令行检查结果

在这里插入图片描述

输入结果文件

在这里插入图片描述
在这里插入图片描述

标签:总结,return,String,房间,Game,command,实训,软件,public
From: https://www.cnblogs.com/istitches/p/17153113.html

相关文章

  • 2.24总结
    今日学习了html制作表单<form>,掌握了基础的表单制作,并了解了表单制作的细节以及提交的细节。其中参悟不深的有:表单提交时数据没有发送给服务器的三种情况。1.表单项没有nam......
  • 数组元素移除问题的总结和延伸
    本文对使用和操作数组时常遇到的一类数组元素移除问题的高效解决方法(O(N))做一总结,并对其中用到的思想做一些总结和延伸。本文以leetcode中的三道算法题为例进行说明。无序......
  • 苹果mac电脑压缩照片怎么压缩 苹果压缩照片的软件
    当我们日常需要将图片进行压缩变小压缩时,如果是Mac电脑应该如何操作呢?本文介绍苹果压缩照片怎么压缩,和苹果压缩照片的软件。BetterZip5下载地址:https://souurl.cn/xAHLY9一......
  • 软件工程开课博客
    1.介绍自己;菜鸟一枚 2.现状、经验和计划;为何选择这个专业:当时听说建民老师管的挺严,选这个专业可以让外力约束自己,否则可能就每天摆烂了。目前是怎么为将来准备的:目前......
  • 路飞项目day01 软件开发流程、PIP永久换源、虚拟环境、路飞项目开始
    一、软件开发流程(重要)​ 我们作为一个后端,虽然一般情况下只专注自己的那一部分事情,但是有时候小公司,人员架构没那么细化,或者老板就是想省钱少招点人,我们就得大致熟悉软件......
  • drf总结
    drf总结drf思维导图:点击下载......
  • 2.24号今日总结
    今天依然发烧没有好,依然身体很难受,但是今天还是学习了maven相关的知识;今天学习啦maven构建Java项目;并且使用IDEA开发工具来构建的IDEA创建MAVEN项目卡在Generati......
  • 第二周星期五每日总结
        今天初步学习了如何通过AndroidStudio开发简单的程序,并通过在网上寻找代码,成功的修改并写出了一个计算器的小程序。但是通过本次的学习我只是简单掌握了如何通......
  • 路飞项目 :软件开发流程 与 路飞项目需求
    目录1软件开发流程2路飞项目需求1软件开发流程#真正的企业里软件从立项到交付整个过程 -立项:确定公司要开发这个软件公司高层 -软件来源 -产品经......
  • 2023.2.24——软件工程日报
    所花时间(包括上课):8.5h代码量(行):0行博客量(篇):5篇今天,上午上了计算机网络和概率论与数理统计,下午上了英语提高与web应用技术开发。我了解到的知识点:1.id、style、class是......