软件建模详细设计是在软件架构模型设计基础上,对系统中各模型进一步细化设计,给出软件程序实现的设计方案。
案例:“环境监测器”功能构件设计
开闭原则设计的好处:
里氏替换原则设计的好处:
案例:鸟类飞行时间计算模块程序设计
//鸟类
class Bird {
protected double flySpeed;
public void setSpeed(double speed) {
flySpeed = speed;
}
public double getFlyTime(double distance) {
return (distance / flySpeed);
}
}
//燕子类
class Swallow extends Bird {
}
//几维鸟类
class BrownKiwi extends Bird {
public void setSpeed(double speed) {
flySpeed = 0;
}
}
package principle;
public class LSPtest {
public static void main(String[] args) {
Bird bird1 = new Swallow();
Bird bird2 = new BrownKiwi();
bird1.setSpeed(120);
bird2.setSpeed(120);
System.out.println("如果飞行300公里: ");
try {
System.out.println("燕子将飞行" +
bird1.getFlyTime(300) + "小时.");
System.out.println("几维鸟将飞行" +
bird2.getFlyTime(300) + "小时.");
} catch (Exception err) {
System.out.println("发生错误了!");
}
}
}
按照里氏替换原则重新设计该模块
完整代码:
// 动物类
class Animal {
protected double runSpeed;
public void setRunSpeed(double speed) {
runSpeed = speed;
}
public double getRunTime(double distance) {
return (distance / runSpeed);
}
}
// 鸟类
class Bird extends Animal {
protected double flySpeed;
public void setFlySpeed(double speed) {
flySpeed = speed;
}
public double getFlyTime(double distance) {
return (distance / flySpeed);
}
}
// 燕子类
class Swallow extends Bird {
// 燕子类可以继承 Bird 类的飞行行为
}
// 几维鸟类
class BrownKiwi extends Animal {
// 几维鸟不能飞,所以我们不实现飞行相关的方法
// 而是使用 Animal 类的跑步行为
// 如果需要,这里可以覆盖跑步速度设置方法或行为
}
依赖倒置原则设计的好处:
案例:顾客购物模块程序设计
顾客类 (Customer) 通过韶关网店(ShaoguanShop)类实现购物,其代码如下:
class Customer {
public void shopping(ShaoguanShop shop) {
//购物
System.out.println(shop.sell());
}
}
顾客若想从婺源网店 (WuyuanShop) 购物,需要对顾客类 (Customer )代码修改:
class Customer {
public void shopping(WuyuanShop shop) {
//购物
System.out.println(shop.sell());
}
}
解决方法:定义“婺源网店”和“韶关网店”的共同接口 Shop ,顾客类 (Customer )面向该接口编程,其代码修改如下:
class Customer {
public void shopping(Shop shop) {
//购物
System.out.println(shop.sell());
}
}
完整代码:
// 定义 Shop 接口
interface Shop {
String sell();
}
// 韶关网店实现 Shop 接口
class ShaoguanShop implements Shop {
@Override
public String sell() {
// 实现卖出商品的方法,返回结果
return "韶关网店销售的商品";
}
}
// 婺源网店实现 Shop 接口
class WuyuanShop implements Shop {
@Override
public String sell() {
// 实现卖出商品的方法,返回结果
return "婺源网店销售的商品";
}
}
// 顾客类,面向 Shop 接口编程
class Customer {
public void shopping(Shop shop) {
// 购物
System.out.println(shop.sell());
}
}
接口分离原则设计的好处:
案例:学生成绩管理程序
单一职责原则设计的好处:
案例:学生工作管理
学生工作主要包括学生生活辅导和学生学业指导两个方面的工作:
迪米特法则的定义是:只与你的朋友交谈,不跟“陌生人”说话。在程序设计中,如果两个软件实体没有直接关系,那么就不直接调用,可以通过第三方转发该调用。
迪米特法则具有以下好处:
案例:明星与经纪人的关系
内聚性意味着构件或者类只封装那些密切关联的属性和操作。
按照内聚性的级别,内聚性分为以下三种,它们的内聚性依次变弱:
一般来说,内聚性越高,构件越易于实现、测试和维护。
耦合性指不同对象之间相互关联的程度。如果一个对象过多地依赖于其它对象来完成自己的工作,这会增加测试、修改的难度,同时降低了对象的可重用性和可移植性。
在详细设计中要尽可能保持对象之间松耦合。但是软件必须进行内部和外部的通信,因此耦合是必然存在的。当两个对象必须相互联系时,应该通过类的公共接口实现耦合,不应该直接依赖于类的实例。
补充例子:
// 定义一个通信接口
interface Communicator {
void sendMessage(String message);
String receiveMessage();
}
// 实现Communicator接口的Email类
class EmailCommunicator implements Communicator {
public void sendMessage(String message) {
System.out.println("Sending email with message: " + message);
}
public String receiveMessage() {
// 假设接收到消息
return "Email message received";
}
}
// 实现Communicator接口的SMS类
class SMSCommunicator implements Communicator {
public void sendMessage(String message) {
System.out.println("Sending SMS with message: " + message);
}
public String receiveMessage() {
// 假设接收到消息
return "SMS message received";
}
}
// 使用Communicator接口的Client类
class Client {
private Communicator communicator;
public Client(Communicator communicator) {
this.communicator = communicator;
}
public void communicate() {
communicator.sendMessage("Hello World!");
System.out.println(communicator.receiveMessage());
}
}
// 在应用程序中使用Client和Communicator
public class CommunicationApp {
public static void main(String[] args) {
Communicator email = new EmailCommunicator();
Communicator sms = new SMSCommunicator();
Client emailClient = new Client(email);
Client smsClient = new Client(sms);
emailClient.communicate();
smsClient.communicate();
}
}
在这个例子中,Client
类不直接与 EmailCommunicator
或 SMSCommunicator
类耦合。相反,它通过 Communicator
接口与它们通信。这允许 Client
类在不知道通信细节的情况下发送和接收消息。因此,如果将来引入了一个新的 Communicator
实现,例如 WhatsAppCommunicator
,Client
类不需要任何修改就能使用它,只需在创建 Client
实例时传入新的通信器即可。这就是通过类的公共接口实现耦合的一个典型例子。
补充例子:
import java.util.ArrayList;
import java.util.List;
// 一个通用的接口定义了操作的契约
interface Operable {
void operate();
}
// 一个具体的类实现了Operable接口
class Printer implements Operable {
@Override
public void operate() {
System.out.println("Printing a document...");
}
}
// 另一个具体的类实现了Operable接口
class Scanner implements Operable {
@Override
public void operate() {
System.out.println("Scanning a document...");
}
}
// 设计一个工作流程类,它可以利用Operable接口操作任何设备
class Workflow {
private List<Operable> operations = new ArrayList<>();
public void addOperation(Operable operable) {
operations.add(operable);
}
public void runAll() {
for (Operable operable : operations) {
operable.operate();
}
}
}
// 演示如何重用Workflow类来操作不同的设备
public class OfficeAutomationApp {
public static void main(String[] args) {
// 创建设备的实例
Printer printer = new Printer();
Scanner scanner = new Scanner();
// 创建工作流并添加操作
Workflow officeWorkflow = new Workflow();
officeWorkflow.addOperation(printer);
officeWorkflow.addOperation(scanner);
// 运行所有操作
officeWorkflow.runAll();
}
}
在这个例子中,Operable
接口允许我们定义一个可以操作任何设备的通用契约。Printer
和 Scanner
类都实现了这个接口,使得它们可以在 Workflow
类中互换使用。这样的设计不仅提高了类的重用性,而且在设计新类时也考虑到了将来的可重用性。例如,如果我们想添加一个新设备类如 FaxMachine
,我们只需要让它实现 Operable
接口,就可以轻松地添加到现有的工作流程中而不需要修改 Workflow
类的代码。
此外,这个例子还展示了如何复用Java开发环境提供的类库,例如 ArrayList
类,来管理 Operable
对象的集合。这种复用标准类库可以提高开发效率,减少错误,并降低开发成本。
以下客户功能模块存在什么设计问题?该如何完善?
接口分离原则, IClient
接口提供的方法太多或不是所有的客户端都需要这些方法,它违反了接口分离原则。客户端不应该被迫依赖于它们不使用的方法。 根据不同的职责将 IClient
接口拆分为更小的接口。详细代码如下:
// 接口负责连接管理
public interface IConnectionManager {
void connect();
void disconnect();
}
// 接口负责数据的发送和接收
public interface IDataTransfer {
void send();
void receive();
}
// 客户端类实现这两个接口
public class Client implements IConnectionManager, IDataTransfer {
@Override
public void connect() {
// 实现连接逻辑
}
@Override
public void disconnect() {
// 实现断开连接逻辑
}
@Override
public void send() {
// 实现发送数据逻辑
}
@Override
public void receive() {
// 实现接收数据逻辑
}
}
问题探讨:以下客户数据图形分析模块存在什么设计问题?该如何完善?
违背单一职责原则,应将该类进行拆分,CustomerDataChart
类负责图表的创建和显示,一个 CustomerDAO
类负责数据访问操作,以及一个 DBUtil
类负责数据库连接。
代码如下:
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
class DBUtil {
public Connection getConnection() {
// 实现数据库连接的逻辑
// 例如使用 JDBC 连接到数据库
return null; // 应返回实际的数据库连接对象
}
}
class CustomerDAO {
private DBUtil util;
public CustomerDAO(DBUtil util) {
this.util = util;
}
public List<Customer> findCustomers() {
// 使用 util.getConnection() 获取数据库连接
// 执行查询并返回客户列表
return new ArrayList<>(); // 应返回实际查询到的客户列表
}
}
class CustomerDataChart {
private CustomerDAO dao;
public CustomerDataChart(CustomerDAO dao) {
this.dao = dao;
}
public void createChart() {
// 使用 dao.findCustomers() 获取数据
// 根据获取的数据创建图表
}
public void displayChart() {
// 显示图表的逻辑
}
}
public class Main {
public static void main(String[] args) {
// 创建 DBUtil 实例
DBUtil dbUtil = new DBUtil();
// 使用 DBUtil 实例来创建 CustomerDAO 实例
CustomerDAO customerDAO = new CustomerDAO(dbUtil);
// 使用 CustomerDAO 实例来创建 CustomerDataChart 实例
CustomerDataChart dataChart = new CustomerDataChart(customerDAO);
// 创建图表
dataChart.createChart();
// 显示图表
dataChart.displayChart();
}
}
图形展示如下:
专属聚合是类之间语义最强的聚合,部分类与整体类之间满足 4 个条件:
从属聚合的语义比专属聚合稍弱,部分类与整体类之间满足 3 个条件:
拥有聚合的语义比从属聚合弱,部分类与整体类之间满足 2 个条件:
成员聚合的语义最低,仅仅是将一组对象组合在一起。
实现继承是指在子类中组合基类(超类)的特征,并允许在必要时以新的实现来重载这些特征。
在扩展继承中,子类组合来自超类的特征,并增加新的特征。
限制继承是指子类组合来自超类的特征,并重载部分继承来的特征。
问题:重载导致子类没有包括超类的所有特征,会带来维护上的问题,可替换性原则失效。
某些类之间具有一定相似的实现,但它们之间不存在泛化关系,即没有概念上的分类关系。方便继承是指将它们中一个类作为其它类的超类。
问题:子类没有包括超类的所有特征,子类与超类之间没有泛化关系,可替换性原则无效。尽量避免采用这种方式实现继承。
软件开发的实际情况很复杂,复杂的问题不会有简单的解决方案。本节引入类图建模的高级概念,包括:
通过设置可见性可以确定类内部的封装程度,决定其他类能否访问该类的元素。应用于类的属性和操作的可见性类型包括:
+ public
公共可见性: 该元素对任何类都可见;- private
私有可见性: 该元素只对本类可见;# protected
保护可见性: 该元素对本类及子类可见;~ package
包可见性: 该元素对同一包中的元素可见.在设计良好的面向对象系统中,大多数操作是公共的,大多数属性是私有的。
public class Visibility {
private int privateAttribute;
public int publicAttribute;
protected int protectedAttribute;
int packageAttribute; // 默认访问修饰符,也称为包访问权限
private void privateOperation() {
}
public void publicOperation() {
}
protected void protectedOperation() {
}
void packageOperation() { // 默认访问修饰符,也称为包访问权限
}
}
( 1 )保护可见性
( 2 )包可见性
( 3 )友元可见性友元可见性用于 c++语言。当一个类需要访问另一个类的私有属性或操作时,可以采用友元可见性,在授予友元关系的类中声明友元操作。
class Book {
private:
void putOnBookShelf();
};
class BookShelf {
public:
friend void Book::putOnBookShelf();
};
导出信息是指从其他元素计算得到的信息。它作为一种冗余信息,其目的是为了增加可读性和信息存取速度。导出信息包括导出属性和导出关联。
限定关联是一对多或多对多关联的约束条件表示。限定关联在二元关联的一端设定属性限定符,即在框中给出一个或多个属性用于约束条件。
如果两个类之间是多对多的关联,且每个关联实例都具有属性值,这时可以使用关联类。关联类具有一个约束,要求对于每一对链接起来的类实例,只能作为关联类的一个实例。如果不能满足这个约束的话,就需要将关联具体化,即使用一个具体化类来代替关联类。这个具体化类与之前的两个类均具有二元关联。
接口用于定义一个类或者构件的功能操作函数集。
接口是一种特殊的类,所有的接口都是构造型为<
的类。在UML中,接口的表示方式有三种: 第一种是接口的图标表示,第二种是接口的修饰表示,第三种是接口的构造型标签表示。
案例: IElectricalEquipment接口定义了turnOn操作和turnoff操作,TV类和Player类均实现了该接口,即实现了turnOn操作和turnoff操作,RemoteControl类使用了IElectricalEquipment接口。
抽象类指不具有实例的类,它通常作为父类,不创建实例对象。抽象类的子类可以实例化。
补充代码:
// 定义一个 Vehicle 基类
abstract class Vehicle {
private String color; // 车辆颜色属性
public Vehicle(String color) {
this.color = color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
// 定义一个抽象方法 drive
public abstract void drive();
}
// Plane 类继承自 Vehicle
class Plane extends Vehicle {
public Plane(String color) {
super(color);
}
// 实现 drive 方法
public void drive() {
System.out.println("Plane is flying.");
}
}
// Bus 类继承自 Vehicle
class Bus extends Vehicle {
public Bus(String color) {
super(color);
}
// 实现 drive 方法
public void drive() {
System.out.println("Bus is driving on the road.");
}
}
// Driver 类与 Vehicle 有关联关系
class Driver {
private Vehicle vehicle;
// Driver 可以驾驶任何类型的 Vehicle
public void driveVehicle(Vehicle vehicle) {
this.vehicle = vehicle;
vehicle.drive();
}
}
类内聚是指类内部元素之间相关性的程度。类耦合是指类之间联系的程度。
内聚和耦合彼此相关联,更强的内聚会导致更弱的耦合,反之亦然。
良好的程序设计应确保在类的内聚与耦合之间达到良好平衡。
为了取得类内聚和类耦合之间的平衡, Riel提出了一些启发规则:
( 1 ) x 类有属性指向 Y 类的实例
( 2 ) x 类有方法引用了 Y 类的实例,如x 使用 Y 类对象作为局部变量;或者返回 Y 类对象
( 3 ) x 类对象调用 Y 类对象方法发送消息
( 4 ) Y 类是 X 类的直接或间接子类
( 5 )X 类方法中输入参数为 Y 类的实例。
( 6 ) Y 类是一个接口,而 X 类实现了该接口。
1 )依赖关系一耦合度最弱
2 )关联关系一耦合度其次弱
3 )聚合关系一耦合度一般
4 )组合关系一耦合度较高
5 )继承关系一耦合度高
6 )实现关系一耦合度最高
类耦合对于对象之间协作实现特定功能是必要的,但它应该尽量被限制在类的层次内,即层内耦合,层间耦合应该最小化。
为了限制类间任意通信,采用迪米特法则(最少知识原则)设计,指明在类操作中只允许将以下对象作为消息目标,即没有直接关系的类之间不交互通信,仅仅有直接关系类进行通信。
Power Designer 建模实践:雇员职位管理设计类图建模
ChatGPT4:
name
(String), sex
(char)getName()
返回 String,getSex()
返回 charusername
(String), password
(String)username
和 password
的获取和设置方法,一个接受用户名和密码并返回布尔值的 login()
方法,以及重写的 getName()
和 getSex()
方法。Employee
类继承自 Person
类,这意味着每个 Employee
都是 Person
,但具有特定于雇员的额外属性和行为,如登录系统的凭证。postname
(String)getPostname()
返回 String,setPostname()
接受一个 String,addPost()
返回一个布尔值。Employee
可以持有的职位或职称。1..1
表示每个 Employee
有且仅有一个 Post
。departmentname
(String)departmentname
的获取和设置方法,addDepartment()
返回布尔值。Employee
与一个 Department
关联,而一个 Department
可以有多个雇员(1..*
关系)。powername
(String)powername
的获取和设置方法。Post
关联的权力或权限。每个 Post
有且仅有一个 Power
,表示一对一的关系。itemname
(String), isvalue
(int)itemname
和 isvalue
的获取和设置方法,addItem()
返回布尔值。Power
类,暗示每个权限可以有多个 Poweritem
实例,这些是更具体的权限或许可。类图还展示了类之间的关联关系:
Employee
与一个 Person
相关联(继承关系)。Employee
可以有一个或多个 Post
(0..*
到 1..1
的关系),但每个 Post
都确切地与一个 Employee
相关联。Post
与一个 Power
关联,每个 Power
与一个 Post
关联(1..1
关系)。Department
可以有多个 Employee
实例,但每个 Employee
都与一个 Department
相关联。这个模型旨在管理组织中雇员的角色和责任。它捕捉了不同组织实体如人员、职位、部门以及与这些职位相关联的权限之间的层次结构和关系。该系统可用于跟踪员工的职位角色、所属部门及其在组织内的相应权限。使用继承和关联确保了清晰、可维护的结构,能够准确反映组织结构。
1 .分析说明如下模型中类之间设计该关系依据是什么?以及它们的耦合度高低。
2 .针对如下 UML 设计类图给出 Vehicle 类、 Car 类、 Bus 类的 Java 编程代码。
1)
2)
import java.util.ArrayList;
import java.util.List;
// Vehicle.java
public interface Vehicle {
void run();
}
// Car.java
public class Car implements Vehicle {
public String name;
public List<Driver> drivers;
public Car(String name) {
this.name = name;
this.drivers = new ArrayList<>();
}
@Override
public void run() {
// Car的run实现
}
public void beforeRun(Oil oil) {
// Car的beforeRun实现
}
public void addDriver(Driver driver) {
this.drivers.add(driver);
}
}
// Bus.java
public class Bus extends Car {
public Bus(String name) {
super(name);
}
// Bus可能有特定的行为和属性,这里只提供基础构造方法
}
完整代码:
import java.util.ArrayList;
import java.util.List;
// Vehicle.java
interface Vehicle {
void run();
}
// Car.java
class Car implements Vehicle {
public String name;
public List<Driver> drivers;
public Car(String name) {
this.name = name;
this.drivers = new ArrayList<>();
}
@Override
public void run() {
// Car的run实现
}
public void beforeRun(Oil oil) {
// Car的beforeRun实现
}
public void addDriver(Driver driver) {
this.drivers.add(driver);
}
}
// Bus.java
class Bus extends Car {
public Bus(String name) {
super(name);
}
// Bus可能有特定的行为和属性,这里只提供基础构造方法
}
// Driver.java
class Driver {
public String name;
public int age;
public List<Car> cars;
public Driver(String name, int age) {
this.name = name;
this.age = age;
this.cars = new ArrayList<>();
}
public void addCar(Car car) {
this.cars.add(car);
}
}
// Oil.java
class Oil {
public String type;
public Oil(String type) {
this.type = type;
}
public void add() {
// Oil的add方法实现
}
}
软件动态交互视图用于描述系统功能的对象之间动态交互行为。顺序图和通信图均属于动态交互模型图。
顺序图也称序列图,它按照从上至下顺序描述对象之间的消息交互,其目的是展示功能逻辑的设计实现。
通信图是另一种类型的动态交互图,它用于表现对象之间的协作关系。通信图由对象以及其关联组成,它强调对象间的连接关系,对象之间消息通信顺序使用序列号表示。
类操作(方法)是指类所能提供的服务或功能函数。类将一组操作函数作为服务提供给系统中的其他类访问。
在 UML 中,类操作的表示语法为:
[可见性] 操作名称 [(参数表)] [:返回类型] [{属性字符串}]
操作名称是动词或动词短语,单词首字母小写。如果有多个单词,则将这些单词连接起来,第一个单词首字母小写,其他单词首字母大写。
ChatGPT4:
类图代表了使用数据传输对象(DTO)模式的用户注册系统设计。这种模式在面向对象设计中常用于软件应用子系统之间的数据传输。这里是类图的每个部分的详细解释:
UserDTO 类:
这是一个简单的 DTO 类,包含两个属性:
userAccount
:一个 String
类型,用来存储用户的账户名。userPassword
:一个 String
类型,用来存储用户的密码。它还提供了两个属性的获取和设置方法,允许其他类访问和修改这些值:
getUserAccount()
:返回 userAccount
字符串。setUserAccount(String userAccount)
:设置 userAccount
字符串。getUserPassword()
:返回 userPassword
字符串。setUserPassword(String userPassword)
:设置 userPassword
字符串。RegisterForm 类:
这个类似乎代表用户填写的注册表单。它包含:
user
:UserDTO
的一个实例,用来保存与用户相关的表单数据。userDao
:IUserDAO
接口的一个实例(下面会解释),可能用于将用户添加到某种类型的数据存储中。IUserDAO 接口:
这是一个定义用户数据访问对象(DAO)契约的接口,包含以下方法:
addUser(UserDTO user)
:一个接受 UserDTO
对象并返回一个表示添加用户到数据存储是否成功的 boolean
值的方法。OracleUserDAO 类:
这是 IUserDAO
接口的一个具体实现,专门设计用来与 Oracle 数据库交互。它实现了 IUserDAO
接口的 addUser
方法。
关系:
RegisterForm
与 UserDTO
有一个组合关系,由实心菱形表示,意味着 RegisterForm
包含并控制 UserDTO
实例的生命周期。RegisterForm
与 IUserDAO
有一个关联关系,由箭头表示,意味着它使用 IUserDAO
接口来访问用户数据。IUserDAO
与 OracleUserDAO
有一个实现关系,由虚线和空心箭头表示。这意味着 OracleUserDAO
承诺实现 IUserDAO
定义的契约。案例:发现操作
在模块功能详细设计中,需要描述功能处理的控制逻辑,如展示条件分支、循环处理,以及并行执行。在顺序图中采用不同类型的片段来表示这些控制逻辑。
UML 2.x中预定义了如下片段:
(1) loop循环片段
在模块功能逻辑设计中,使用loop片段表示重复执行一些操作。
(2)para并行片段
在模块功能逻辑设计中,使用para片段表示执行一些并行操作。
(3)alt条件片段
在模块功能逻辑设计中,使用alt片段表示根据条件执行操作。alt片段表达if-then-else逻辑。
(4) opt选项片段
在模块功能逻辑设计中,使用opt片段根据当条件执行选项操作。opt片段表达if…then逻辑。
在设计有较多相同处理逻辑的模块时,可以采用交互引用复用已有处理逻辑,被引用的处理逻辑采用标签 ref 标注。
在如下订单提交模块序列图模型中,包含了哪些处理逻辑?并分别说明各交互对象的对象类型。
订单结账和信用卡支付。
Customer、Payment Processor为参与者, Order Checkout、CreditCard Payment为控制类对象, Checkout Page为边界类对象 ,Order、OrderItem、Item为实体类对象。
状态机图是对系统中对象的状态变化逻辑进行建模,它描述类对象随时间变化的行为状态,以及对象受事件影响如何进行状态变迁。
状态机图建模步骤:
案例:微波炉工作的状态机图
ChatGPT4:
状态:
转换和触发事件:
针对如下电梯对象的状态机图模型,如何编写其Java控制程序?
代码均为简化代码,参考思路即可:
1.定义电梯的状态和事件:
public enum ElevatorState {
IDLE,
MOVING_UP,
MOVING_DOWN,
OPEN_DOORS,
CLOSED_DOORS
}
public enum ElevatorEvent {
CALL_UP,
CALL_DOWN,
MOVE_UP,
MOVE_DOWN,
DOORS_OPEN,
DOORS_CLOSE,
TIMEOUT
}
2.创建电梯的控制类
public class ElevatorControl {
private ElevatorState currentState;
public ElevatorControl() {
this.currentState = ElevatorState.IDLE;
}
public void handleEvent(ElevatorEvent event) {
switch (currentState) {
case IDLE:
switch (event) {
case CALL_UP:
openDoors();
currentState = ElevatorState.OPEN_DOORS;
break;
case CALL_DOWN:
// Similar logic for CALL_DOWN
break;
// Handle other events
}
break;
case MOVING_UP:
switch (event) {
case MOVE_UP:
// Logic for moving up
break;
case TIMEOUT:
currentState = ElevatorState.IDLE;
break;
// Handle other events
}
break;
// Implement logic for other states
}
}
private void openDoors() {
// Logic to open elevator doors
System.out.println("Doors are opening.");
}
// Define other methods such as closeDoors(), moveUp(), moveDown(), etc.
}
3.使用控制类响应事件
public class ElevatorSystem {
public static void main(String[] args) {
ElevatorControl elevator = new ElevatorControl();
// Simulate events
elevator.handleEvent(ElevatorEvent.CALL_UP);
elevator.handleEvent(ElevatorEvent.DOORS_CLOSE);
elevator.handleEvent(ElevatorEvent.MOVE_UP);
// Add more events as needed
}
}
实现视图是对系统的实现结构建模,包括如下模型图:
端口是指构件一个对外交互点。端口显示为一个小正方形,放置在构件方框的边界上。
在 UML 软件架构建模设计中,主要使用如下连接器将构件的端口进行连接。
作为一种选择, UML 还允许将连接器按如下方案连接构件端口。
若有多个构件使用相同接口访问另一构件接口, UML 允许将连接器按如下方案连接构件端口。
身份认证构件 (Authentication)端口与订单构件 (Orders) 端口均使用相同请求接口(lCustomers)连接客户构件(:Customers )端口的供给接口lCustomers。
委托连接器是将构件的端口连接到实现该行为的对象。它表示消息到达一个端口后,将被传递给内部目标对象进行处理。
案例:电子商务系统的构件图
节点
构件在节点中部署
构件需要在节点设备中运行。在建模时,需要将构件在节点中进行部署
案例:电子商务系统部署图
UML 中包表示为左上方带有小矩形的矩形。包的名称采用字符串,简单名仅包含名称字符串,全限定名则以本包所处的外围包的名称作为前缀。
包可以控制protected所包含的内部元素的可见性,即外部元素访问包内元素的权限:
+ public
公共可见性: 对它所在包和内嵌包的对象可见,也对所有引入它的包及其子包中对象可见;- private
私有可见性: 只对它所在包中对象可见;# protected
保护可见性: 对它所在包和内嵌包中对象可见;案例:应用包图描述系统的软件架构
针对如下股票投资分析系统构件模型,分析构件之间关系如何设计?
ChatGPT4:
在这个股票投资分析系统的构件模型中,构件之间的关系是按照客户端-服务器架构设计的。客户端包含用户界面(GUI)、图形库(Graphing Lib)、客户端会话(Client Session)和股票组合(Stock Portfolio)构件。服务器端包含认证服务器(Authentication Server)、服务器会话(Server Session)、股票市场分析器(Stock Market Analyzer)和投资组合数据库(Portfolio DB)构件。
客户端的GUI用于展示信息和接收用户输入,图形库用于数据可视化。客户端会话管理用户与系统的交互,而股票组合构件负责管理用户的个人投资组合信息。这些客户端构件通过API与服务器端的构件交互。服务器端的认证服务器负责处理登录和安全认证,服务器会话维护与客户端的连接状态。股票市场分析器是系统的核心,负责分析股票市场数据和生成投资建议,而投资组合数据库存储用户的投资组合信息。
客户端与服务器之间的交互通过网络进行。例如,用户通过GUI发起请求,客户端会话将请求发送到服务器,服务器会话接收请求并与认证服务器进行认证,然后由股票市场分析器处理请求。结果通过服务器会话返回给客户端会话,并最终通过GUI展示给用户。
此外,系统还接入了第三方服务,如彭博数据库(Bloomberg DB),这提供了额外的市场数据,股票市场分析器可能会使用这些数据来增强分析结果的准确性。
针对如下房地产按揭交易系统部署模型,分析各要素之间关系如何设计?
针对如下电商系统软件架构模型,分析包之间关系如何设计?
《use》关系表示使用依赖,Web Shopping依赖Payment,Mobile Shopping依赖Payment…
《merge》关系表示合并,Web Shopping、Mobile Shopping、Phone Shopping、和Mail Shopping合并之后就拥有了Shopping Cart的全部功能 。也表明了它们共享一些在“Web Shopping”包中定义的通用功能。
《Access》关系表示私有引入,比如代码中的指定包名类名 。Payment可以访问Shopping Cart中的特定功能或类,但这种访问是受限的。
《Import》关系表示公共引入,比如Java中的import之后,就可以直接使用import包中的类了。一旦“Shopping Cart”公共导入了“Inventory”,它就可以直接使用“Inventory”中定义的公共类和接口。
建立系统静态模型类图。建立类图需要确定系统中的类,确定类的属性,确疋类之间的关系。根据系统动态模型确定类的操作并完善类图。
( 1 )确定系统中的类
( 2 )确定类的属性
( 3 )确定类之间的关系,创建系统类图
系统详细设计阶段,针对用例图中的每一个用例,考虑如何通过对象之间的协作来完成用例的功能。采用顺序图或通信图对用例功能进行设计建模,采用状态机图对类的行为状态进行设计建模。
Book 对象是图书管理系统中具有明显状态变化的对象,图书借阅业务都与Book对象状态有关。Book对象具有如下状态: 新书 (NewBook) 、可借阅预定(Available) 、被预定 (Reserved) 、被借阅 (Borrowed) 、被删除 (Deleted)。
Borrower对象也具有比较明显的状态,因此也采用状态机图对其建模。
Borrower 对象具 有 如下状态: 新建 (NewUser) 、未预定未借书 (NoLoanReserve) 、有预定 (HasReserve) 、有借书 (HasLoan) 、有预定有借书 (HasLoanReserve) 、被删除 (Deleted)。
Borrower类需要提供
Book类需要提供
Loan类需要提供
针对图书借阅管理系统如下构件,如何设计系统部署图模型,并在部署图中给出部署关系和运行环境(Apache、JBoss、PostgreSQL、Ubuntu)。
1)页面构件:borrowBook.jsp、returnBook.jsp、reserveBook.jsp、searchBook.jsp、viewBook.jsp、borrowerInfo.jsp,
2)控制构件:borrowBook.java、returnBook.java、reserveBook.java、searchBook.java、viewBook.java、borrowerInfo.java,
3)实体构件:book.java、reservation.java、loan.java、borrower.java,
4)数据库表:BookInfo、Reservation、Loan、Borrower、BookType
ChatGPT4:
我们可以按照三层架构来组织这些构件:
borrowBook.jsp
, returnBook.jsp
等。borrowBook.java
, book.java
等。BookInfo
, Loan
等。现在,我将详细设计一个系统部署图模型来展示这些构件是如何部署和相互作用的:
所有这些组件都部署在Ubuntu操作系统上,确保系统兼容性和稳定性。