软件技术

编译环境设置

下载Maven

到这个链接 里下载maven的包

image-20200507114645077

然后解压到某个目录下,

配置环境变量

把maven目录下的bin目录添加到path里面

image-20200507114852666

然后可以用 mvn -v 检查配置情况

image-20200507115027756

Lecture 2

Software lifecycle

分析问题

要从问题中提取功能,然后记录在backlog上:

比如说:

Bumpers is a game where cars drive on a game board and can crash each other. 
 In each collision, there is a winning car.The car that wins all collisions is the winner of the game.The player can start and stop the game. When the game is started, music is played. A car can be either fast or slow. There is one car controlled by the player. 
 The player can steer the direction of the car with the mouse and change its speed. The game should be platform independent. 
 It should visualize different parameters of the car, e.g. the speed, consumption and location of the car. When cars crash, there has to be a sound effect. 
 The game should support different collisions.The determination of the collision winner should be changeable during gameplay.

所以我们可以依次列出一个清单

  1. Cars drive on the game board
  2. Cars collide with each other and each collision has a winning car
  3. The winner of the game is the car that wins all the collisions
  4. The player starts and stops the game
  5. Music plays when the game begins and stops to play when the game ends
  6. The game supports different car types
  7. The player steers the car with the mouse
  8. The player can change their car’s speed
  9. The game should be compatible with multiple platforms
  10. The speed, consumption, and location of the player’s car is visualized in an instrument panel
  11. Collisions follow the “right before left” rule, and thus right-most cars win the collisions
  12. A crash sound and/or animation plays when two cars collide
  13. The game supports different collisions, the determination of the winner is changeable during game play.

UML 图

Scenario格式

image-20200726200629385

Use Case Diagram

他是可以从用户的角度展示一个系统功能的图,比如

image-20200509133954223

Actor 是使用这个系统的人

  • 用户
  • 外部系统
  • 物理环境(天气)
Association
  • «includes»

    重复使用一个功能

  • «extends»

    不是总是发生的情况

比如:

Collect money可能会被其他东西使用。Out of order是一个例外情况,不是总是发生

image-20200509134454165
Bumper的Use Case 图

(1)Cars drive on the game board

(4)The player starts and stops the game

  1. Music plays when the game begins and stops to play when the game ends
image-20200509134901978

Class Diagram

比如说这样一个描述类的图,有方法,属性还有关系

image-20200509141903626
类的属性
image-20200509144207152
  • 类名斜线,表示是个abstract类
  • Attribute 中
    • - 表示private
    • + 表示public
    • ~ 表示在包中可见(不加修饰符)
Association

Inheritance: 继承 Realization: 接口实现 Dependency: 依赖 Aggregation 拥有关系 Compositon 构成关系

  • Compositon 和Aggregation类似,但是类不能独立存在,必须依附于其中一个类

image-20200509143405160

  • Dependency 中,一个类中的方法会用到另一个类,比如

    Dependency
Cardinality

这个是在关系上的数字。比如1个或者多个拥有关系

Cardinality

为了画出这样一个图首先我们要找出主要的对象

Abbot’s Technique

我们可以找出关键词汇,来帮我们建图

image-20200509142131334
Bumper的类图
image-20200509142659653

我们提取出其中的关键文字:

image-20200509142725717

Analysis, design, implementation and delivery of Bumpers

Lecture 3 需求分析

需求的种类

  • Functionality requirements

    actors,

  • Nonfunctional requirements

    • Quality requirements:
      • Usability
      • Realiability
      • Performance
      • Supportability

Functionality

它指的是系统与外部的交互

  • Relationship of outputs to inputs
  • Response to abnormal situations
  • Exact sequence of operations
  • Validity checks on the inputs

它需要写出一个动作的形式,比如

  • Withdraw money
  • Deposit mony
  • Transfer money
  • Loas cash card

Leture 4 系统设计 I

系统设计的8大问题

  1. 设计目标 Design goals

  2. 子系统分解 Subsystem decomposition

  3. 并发 Concurrency

  4. 硬件软件映射 Hardware/software mapping

  5. 管理现有数据 Persistent data management

  6. 全局资源处理 Global resource handling

  7. 软件控制 Software control

  8. 边界条件 Bondary conditions

它和需求分析的关系

image-20200527090243368

设计目标 Design Goal

任何一个Nonfunctional requirment是一个设计目标。

取舍 trade-offs

设计目标经常会互相冲突

  • Functionality vs. usability

    有100个功能的系统未必好用

  • Cost vs. robustness

    低造价的系统往往不会检查错误

  • Efficiency vs. portability

  • Rapid development vs. functionality

  • Cost vs. reusability

  • Backward compatibility vs. readability

    使得系统兼容会是代码可读性下降

子系统分解

子系统:类,关系,事件的集合

服务:子系统提供的外部可见的操作

子系统的内聚与耦合 Coupling and cohesion of subsystems

目标是在容许变换下减少系统复杂性

内聚Cohesion:在一个系统间类之间的依赖

耦合Coupling: 子系统间的依赖

系统分化模块要做到高内聚、低耦合

实现高内聚

交互都是这个系统间的,不跨越系统

  • 操作都是在相同的属性上
  • 操作实现了相同的功能或服务
实现低耦合

调用一个类不需要知道这个类内部的东西

  • 小的接口
  • 信息隐藏
  • 无全局数据
  • 交互都是在子系统内部

架构风格

它是子系统分解的模式

UML 组件图 component diagram

它可以用组件和依赖关系的形式给出最高层次的系统设计的模型

  • 提供的接口和使用某个接口
  • 依赖 dependency
  • 端口 port
image-20200527094624898

Lecture 5 系统设计II

架构风格

MVC 架构风格

它可以用于解决高耦合(high coupling)的系统问题。

  • Model: 处理和存储应用的主要数据 (entity objects)
  • View: 把信息展示给用户 (boundary objects)
  • Controller: 与用户交互且更新model

View和Controller共同构成用户接口

Repository架构风格

几个独立的程序在一起工作并且组成一个repository. 子系统只从repository里访问/修改数据

比如编译器的架构

image-20200528103756370

用图像表示架构风格

  • 组件Component 代表subsystem
  • 连接 Connectors 代表 communication
层次架构 Layered architectural style
image-20200528104226593
客户端服务架构 Client server architectural style
image-20200528104214045

并发

它被用来解决非功能性需求中的:性能,响应时间,延时,可用性。

使用多线程的时候要注意同步

硬件软件映射

怎样把类模型映射到硬件/软件上。如何实现子系统

  • Control objects -> processor
  • Entity objects -> memory
  • Boundary objects -> input/output device

部署图 deployment diagram

image-20200528114606418

稳固的数据管理

  • File system
  • Database system

全局资源处理

在多用户系统中,不同用户对资源的权限不同。

我们可以使用 access matrix来做

image-20200528115312760

软件控制

我们可以选择中心化的和去中心化的软件控制. 在communication diagram中,我们可以看到软件的中心化程序

  • Fork diagram
image-20200528115933561
  • Stair diagram
image-20200528115950678

边界条件

  • 初始化 Initialization: 从开始到准备状态
  • 停止 Termination: 清理资源
  • 错误 Failure: 错误,bugs

我们可以用 use case 来建模

  • Actor: often the system administrator
  • Interesting use cases:
    • Start up of a subsystem
    • Start up of the full system
    • Termination of a subsystem
    • Error in a subsystem or component, failure of a subsystem or component
image-20200528120520736

Object Design

代码重用的类型

  • 黑盒重用 (aggregation and composition)

  • 白盒重用 (inheritance)

设计模式

Bridge

Composite

Proxy

Adapter

Facade

Testing

Unit testing

Integration testing

Test all interfaces between subsystems and the interaction of subsystems

Stub

用来替代某个被调用的组件

Driver

用来调用其他组件

Bottm up

image-20200726114706362

Top down

image-20200726114754782

System testing

Dynamic analysis

Model based testing

Object oriented testing

Correct

  • In object oriented testing, the test model can contain dummy objects.
    • SUT means system under test
    • In object oriented testing doubles replace the SUT's collaborators during testing
    • Typically, a factory or the test case initailizes mock objects. Mock objects are not part of the system model! There must not be a dependency from the system model to mock objects.
  • In integration testing,
    • bottom up integration testing is useful for testing real time systems. Because we have heavily rely on performance in real time systems. Bottom up integration testing makes sure to test the underlying funcitonality first. No doubles are needed to verify the expected behaviour.
    • top down integration testing can result in a lot of doubles if the lowest level of the system contains many methods. No drivers are needed.
    • vertical integration testing allows to always have an executable version of the system. We can test how the layers work togethor for specific functionality and have a working the system.
    • They only cover one layer in the beginning. only at the end they cover all layers.(not always cover all layers).
  • Unit Test
    • Unit tests can be executed with JUnit
    • Unit tests are typically used in development environments
    • Unit tests can test whether a method's observed output is the same as the expected output
    • An assertion verifies that a condition is met when the code is executed

Wrong

Lecture 11

Git

Correct

  • Git
    • To promote local changes, a developer needs to add, commit and push.
    • Pull is a compound command to fetch and merge changes from the remote into the local repository
    • Push will upload the commits from the local repository to the remote
    • Merge conflicts should be resolved in the local repository
    • To fetch changes from the remote repository, you need to be connected to the remote repository(online)
    • The repository can be restored from a programmer's computer if the server crashes
    • Distributed version control systems have a higher learning curve because their users need to understand multiple commands and actions,which is a disadvantage.
    • Branches are lightweight
    • Programmers could exchange commits directly without the need to store the version on the remote repository
    • A change policy can, e.g., guarantee that each promotion conforms(遵从) to commonly accepted criteria(标准)
    • In certain cases, a change request from the customer can also be rejected
  • Software Quality
    • Different people have a different understanding of software quality
    • Quality aspects can change over time
    • Quality is difficult to measure
    • Quality can be very subjective
  • Advantages of code reviews
    • There are more developers who understand the code
    • Developers communicate more with each other
  • Disadvantages of code reviews
    • Reviewing code cost times. Code reviews slow down the initial development
  • Static code analysis can find certain issues,but there are many issue types that can be found with a manual code review(not automated)
  • activitys in Quality management
    • Quality assurance
    • Quality control
  • prevent code duplication
    • Refactoring
    • Delegation
    • Inheritance
  • Scrum
    • in scrum changes can occur all the time and can be integrated into the Product Backlog, as Scrum relies on an empirical process model.
    • The Scrum Master is not a traditional project leader. The developers have much more control.
    • Scrum Master should make sure that the team follows the Scrum process
    • Trying out the software and providing feedback are responsibilities of the Product Owner. However, the product owner is not necessarily also an end user of the software.
  • The Waterfall Model relies on a defined process model and therefore does not take changes into account.

Wrong

  • Merge conflicts are resolved on the remote repository.
  • pull is a compound command, composed of fetch and clone.
  • Fetching changes can be done offline.
  • Code reviews can be completely automated

Software Architecture

Correct

  • Process Control
    • A software architecture is an instance of an architectural style. The architecture style then serves as a pattern for a subsystem decomposition
    • As empirical processes see changes as opportunities, they deal better with them then defined processes, which see them as errors.

Wrong

Process Control

Correct

Wrong

项目: Space Invader

Problem Statement

  • They have a high fun factor, no learning curve and short startup times.

  • As the duration of these games is short

  • TUM wants to have a simple and easy single player game

  • offer it for students to play during boring lectures

  • The data about when and how successfully the game is played shall be used to assess the quality of TUM’s educational program.

  • The game shall be derived from the classic game Space Invaders

  • adjust the gameplay or the graphics for the purpose of being played during lectures.

  • The game should collect data about when the game is being played and how well the player is doing

  • it is possible to derive some assertions about how captivating the lecture was, that the player was supposed to pay attention to.

需求分析

Functional Requirements

  • Show scores (Evaluate how success the game is played)

  • Get Time data

  • Get Lecture Information

  • derive some assertions about how captivating the lecture was

  • start game

  • adjust pictures

Space Invader
  • move the spacecraft

  • shoot bullet

  • evaluate collision

Nonfunctional Requirements

  • Usability:
    • The player need at most 3 clicks to start a game.
    • The player need at most 3 buttons to control the spacecraft
  • Performace: The startup should finish in 1 second.

FR1: Show scores (Evaluate how success the game is played) FR2: Get Time data FR3: Get Lecture Information FR4: derive some assertions about how captivating the lecture was FR5: start game FR6: shoot bullet

NFR1 [Usability]: The player need at most 3 clicks to start a game. NFR2 [Usability]: The player need at most 3 buttons to control the spacecraft NFR3 [Performace]: The startup should finish in 1 second.

JavaFX

创建项目

https://openjfx.io/openjfx-docs/#maven

项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package de.tum.in.ase.eist.tumspaceinvaders;

import de.tum.in.ase.eist.view.GameBoardUI;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;


/**
* JavaFX App
*/
public class TumSpaceInvadersApplication extends Application {

public GameBoardUI gameBoardUI;

@Override
public void start(Stage stage) {
BorderPane rootBorderPane = new BorderPane();

// 控件写在这里

// 根场景
Scene scene = new Scene(rootBorderPane, 400, 400);

// 读取样式表
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());

stage.setScene(scene);
stage.show();
}

public static void main(String[] args) {
launch();
}

}

这两个文件的包目录是一样的

image-20200617183908900

javaFX里面的控件是树状排列的

stage -> scene -> rootBorderPane

​ |

​ -> label

控件

Label

1
2
3
4
5
6
BorderPane rootBorderPane = new BorderPane();

Label label1 = new Label("Hello World"); // 创建控件
rootBorderPane.setCenter(label1); // 显示在中间

Scene scene = new Scene(rootBorderPane, 400, 400);
image-20200617184219271

Button

1
2
3
4
Button btn = new Button("Click Me");
rootBorderPane.setCenter(btn);
MyEventHandler myEventHandler = new MyEventHandler();
btn.setOnAction(myEventHandler);
事件处理器

内部类写法

1
2
3
4
5
6
7
8
9
private class MyEventHandler implements EventHandler<ActionEvent> {

@Override
public void handle(ActionEvent event) {
// TODO Auto-generated method stub
System.out.println("hello");
}

}

匿名类写法:

1
2
3
4
5
6
7
8
9
btn.setOnAction(new EventHandler<ActionEvent>() {

@Override
public void handle(ActionEvent event) {
// TODO Auto-generated method stub
System.out.println("hello");
}

});

lambda表达式写法

1
btn.setOnAction(e -> System.out.println("hello"));

Image

1
2
3
4
5
6
7
8
9
Image image = new Image(new File("resources/bgimg1.jpg").toURI().toString());
ImageView imageView = new ImageView();
imageView.setImage(image);

double width = image.getWidth();
double height = image.getHeight();

Scene scene = new Scene(rootBorderPane, width, height);
rootBorderPane.setCenter(imageView);

添加其他窗口

可以用 SceneBuilder 来可视化定制界面: https://gluonhq.com/products/scene-builder/

打开就可以用图形界面来编辑窗口。

image-20200724093035896

编辑完成了之后,可以得到一个 .fxml 文件,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.Scene?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.stage.Stage?>

<Stage fx:id="stage" title="Shop" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.tum.in.ase.eist.view.ShopUI">
<scene>
<Scene>
<AnchorPane prefHeight="485.0" prefWidth="586.0">
<children>
<Button fx:id="buyDestroyerBtn" layoutX="39.0" layoutY="212.0" mnemonicParsing="false" onAction="#buyDestroyer" text="BUY" />
<ImageView fx:id="imgDestroyer" fitHeight="100.0" fitWidth="180.0" layoutX="39.0" layoutY="59.0" pickOnBounds="true" preserveRatio="true" />
<Label layoutX="39.0" layoutY="166.0" text="Destroyer 200$" />
<Button fx:id="buySuperCraftBtn" layoutX="293.0" layoutY="212.0" mnemonicParsing="false" onAction="#buySuperCraft" text="BUY" />
<ImageView fx:id="imgSuperCraft" fitHeight="100.0" fitWidth="180.0" layoutX="293.0" layoutY="52.0" pickOnBounds="true" preserveRatio="true" />
<Label layoutX="293.0" layoutY="166.0" text="SuperCraft 500$" />
<Button fx:id="buySuperBulletBtn" layoutX="39.0" layoutY="439.0" mnemonicParsing="false" onAction="#buySuperBullet" text="BUY" />
<ImageView fx:id="imgSuperBullet" fitHeight="100.0" fitWidth="180.0" layoutX="39.0" layoutY="264.0" pickOnBounds="true" preserveRatio="true" />
<Label layoutX="39.0" layoutY="393.0" text="SuperBullet 100$" />
<ToolBar layoutY="7.0" prefHeight="17.0" prefWidth="587.0">
<items>
<Label text="Your Money: " />
<Label id="moneyLbl" fx:id="moneyLabel" text="Label" />
</items>
</ToolBar>
<Button fx:id="continueBtn" layoutX="475.0" layoutY="427.0" mnemonicParsing="false" onAction="#continuefunc" text="continue" />
</children></AnchorPane>
</Scene>
</scene>
</Stage>

首先我们要绑定对应的类:也就是设置 fx:controller 属性为对应的类, 我这里是 de.tum.in.ase.eist.view.ShopUI.

然后再 ShopUI 类里,可以用Show Sample Controller Skeleton来生成对应的代码

image-20200724093621722

再copy到ShopUI 类里面

image-20200724093820085

并且在module.info里面要写 exports [package] to javafx.xml 其中 [package]ShopUI 所在的包. 然后并且还要写一行 opens ...

1
2
3
4
5
6
7
8
9
10
11
12
module de.tum.in.ase.eist.tumspaceinvaders {
requires javafx.controls;
requires javafx.media;
requires javafx.base;
requires javafx.graphics;
requires javafx.fxml;
exports de.tum.in.ase.eist.tumspaceinvaders;

exports de.tum.in.ase.eist.view to javafx.fxml;
opens de.tum.in.ase.eist.view to javafx.fxml;
}

然后可以从代码中导入预设

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private void openShop() {
Platform.runLater(() -> { // 与图像界面交互,要用runLater
try {

FXMLLoader loader = new FXMLLoader();
Stage stage = loader.load(new FileInputStream("resources/layout/ShopUI.fxml"));
ShopUI shopUI = (ShopUI)loader.getController();

this.shop.setShopUI(shopUI); // 设置一下参数
this.shop.getShopUI().setStage(stage);
this.shop.getShopUI().setShop(this.shop);
this.shop.setPlayer(this.gameBoard.getPlayer());
this.shop.setGameBoard(this.gameBoard);

this.shop.getShopUI().refresh();
this.shop.getShopUI().start(new Stage()); // 打开


} catch (Exception e) {
e.printStackTrace();
}
});

}

添加Junit测试

pom.xml 中添加下面的依赖

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>4.2</version>
<scope>test</scope>
</dependency>

然后创建test文件夹

一般就可以出现junit的依赖了,如果没有的话检查一下 .classpath 文件, 可以手动添加这个

1
2
3
4
5
6
7
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/> <!-- 这个要有 -->
</attributes>
</classpathentry>

pom.xml配置文件

打包项目

打包的时候,主程序不要extend Application 不然会出现找不到Javafx 的错误。 可以改成下面的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class TumSpaceInvaders {
public static void main(String[] args) {
Application.launch(TumSpaceInvadersApplication.class);
}
}

public class TumSpaceInvadersApplication extends Application {

private GameBoardUI gameBoardUI;

@Override
public void start(Stage stage) {

this.gameBoardUI = new GameBoardUI(Thread.currentThread());
Scene scene = new Scene(gameBoardUI.getRootBorderPane());
// scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());

stage.setTitle("Tum Space Invaders");
stage.setScene(scene);
stage.show();

}

}

添加plugin

pom.xmlbuild中加入下面的插件,记得修改mainClass 等参数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 <plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target</outputDirectory>
<resources>
<resource>
<directory>${basedir}/resources</directory>
<filtering>true</filtering>
<targetPath>${basedir}/target/resources</targetPath>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<!-- mvn clean compile assembly:single -->
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>de.tum.in.ase.eist.tumspaceinvaders.TumSpaceInvaders</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>

执行命令

在终端执行这个命令来打包

1
mvn clean compile assembly:single

或者在eclipse中选择 Run As -> Maven build ... 然后再goal 中输入 clean compile assembly:single

执行完成后,会出现一个jar文件, 可以这样来执行jar程序.

1
java -jar xxx.jar