软件建模具体规划概述
软件建模具体规划方针
软件建模具体规划是在软件架构模型规划根底上,对体系中各模型进一步细化规划,给出软件程序完结的规划方案。
软件建模具体规划准则
开闭准则
- 软件实体(类、构件等)应该对功用扩展具有开放性,对代码修正具有封闭性。
- 当运用需求改动时,在不修正软件实体源代码的前提下,就能够扩展模块的功用,使其满意新的需求。
事例:“环境监测器”功用构件规划
开闭准则规划的优点:
- 在不修正原有代码根底上,能够扩展新功用。
- 进步代码的可复用性及可保护性。
里氏 (Liskov) 替换准则
- 子类能够扩展基类的功用,但不能改动基类原有的功用。
- 子类在承继基类时,除了增加新的办法且完结新增功用外,不要重写基类的办法代码。
- 子类有必要遵守基类与外部类之间的隐含约定。
里氏替换准则规划的优点:
- 处理了承继重写父类带来的可复用性变差问题。
- 进步代码的可复用性及可保护性。
事例:鸟类飞翔时刻核算模块程序规划
//鸟类
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();
}
}
图形展现如下:
软件建模具体规划内容
- 在剖析类根底上,对软件静态结构模型的类图进行具体规划。各个功用构件均需给出规划类模型。
- 针对构件功用,剖析方针之间的交互联系,给出功用构件逻辑完结的动态行为交互图模型具体规划。
- 剖析方针生命周期的状况改变,给出方针状况变迁的状况机图模型具体规划。
- 对反映软件物理完结模型的构件图和布置图进行具体规划。
UML 软件静态结构视图建模
软件静态结构细化规划
- 静态结构视图用来标明软件体系的类程序组成结构,同时也反映各个类中封装的数据与操作办法。
- 静态结构视图支撑面向方针程序编程。
类的聚合联系细分
专属聚合 (Exclusive0wns)
专属聚合是类之间语义最强的聚合,部分类与全体类之间满意 4 个条件:
- 部分类对全体类具有存在依靠性,删去全体类时,部分类也被删去。
- 具有传递性,假如方针 C1是 B1 的一部分,而且 B1 是 A1 的一部分, C1 也是 A1 的一部分。
- 具有非对称性,假如 B1 是 A1 的一部分,则 A1 不是 B1 的一部分。
- 具有固定性,假如 B1 是 A1 的一部分,则它绝不是 Ai (i!=1)的一部分。
隶属聚合 (0wns)
隶属聚合的语义比专属聚合稍弱,部分类与全体类之间满意 3 个条件:
- 部分类对全体类具有存在依靠性,删去全体类时,部分类也被删去。
- 具有传递性,假如方针 C1 是 B1 的一部分,而且 B1 是 A1 的一部分,则 C1 是 A1 的一部分。
- 具有非对称性,假如 B1 是 A1 的一部分,则 A1 不是 B1 的一部分。
具有聚合 (Has)
具有聚合的语义比隶属聚合弱,部分类与全体类之间满意 2 个条件:
- 具有传递性,假如方针 C1 是 B1 的一部分,而且 B1 是 A1 的一部分,则 C1 是 A1 的一部分。
- 具有非对称性,假如 B1 是 A1 的一部分,则 A1 不是 B1 的一部分。
成员聚合 (Member)
成员聚合的语义最低,仅仅是将一组方针组合在一起。
- 不具有存在依靠性、传递性、非对称性、固定性。
- Member 聚合具有组合独立方针的特征。
- 标明一组方针作为一个高层复合方针来考虑。
- 一个方针能够同时归于一个以上的复合方针,因此 member 聚合的多重性能够是多对多。
泛化与承继
- 泛化是指多个类的公共特征笼统到一个更一般化的类中,它描绘类之间的一般与具体联系。
- 承继是指子类复用基类(超类)特点与操作的机制。
完结承继
完结承继是指在子类中组合基类(超类)的特征,并允许在必要时以新的完结来重载这些特征。
扩展承继
在扩展承继中,子类组合来自超类的特征,并增加新的特征。
束缚承继
束缚承继是指子类组合来自超类的特征,并重载部分承继来的特征。
问题:重载导致子类没有包含超类的一切特征,会带来保护上的问题,可替换性准则失效。
便利承继
某些类之间具有一定相似的完结,但它们之间不存在泛化联系,即没有概念上的分类联系。便利承继是指将它们中一个类作为其它类的超类。
问题:子类没有包含超类的一切特征,子类与超类之间没有泛化联系,可替换性准则无效。尽量防止选用这种办法完结承继。
高档类图建模
软件开发的实际状况很复杂,复杂的问题不会有简单的处理方案。本节引入类图建模的高档概念,包含:
- 可见性
- 导出信息
- 束缚相关
- 相关类与具体化类
可见性
经过设置可见性能够确认类内部的封装程度,决定其他类能否拜访该类的元素。运用于类的特点和操作的可见性类型包含:
-
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 )包可见性
- 具有包可见性类的特点和操作能够被处于同一包中的其他类拜访。
- 包可见性是 Java 言语默许的可见性。
( 3 )友元可见性友元可见性用于 c 言语。当一个类需求拜访另一个类的私有特点或操作时,能够选用友元可见性,在授予友元联系的类中声明友元操作。
class Book {
private:
void putOnBookShelf();
};
class BookShelf {
public:
friend void Book::putOnBookShelf();
};
导出信息
导出信息是指从其他元素核算得到的信息。它作为一种冗余信息,其意图是为了增加可读性和信息存取速度。导出信息包含导出特点和导出相关。
- 导出特点是指能够由其他信息导出的特点。
- 导出相关是指由其它相关导出的相关。
- 导出信息的 UML 标明是在导出特点名或导出相关名前面加上一条斜线“/”。
束缚相关
束缚相关是一对多或多对多相关的束缚条件标明。束缚相关在二元相关的一端设定特点束缚符,即在框中给出一个或多个特点用于束缚条件。
相关类与具体化类
假如两个类之间是多对多的相关,且每个相关实例都具有特点值,这时能够运用相关类。相关类具有一个束缚,要求对于每一对链接起来的类实例,只能作为相关类的一个实例。假如不能满意这个束缚的话,就需求将相关具体化,即运用一个具体化类来替代相关类。这个具体化类与之前的两个类均具有二元相关。
接口与笼统类
接口
接口用于界说一个类或许构件的功用操作函数集。
- 接口界说一组操作,但不界说操作的完结。
- 接口一般不界说特点,只要界说操作,而且一切操作都隐含是公共的、笼统的可视性。
- 在完结接口的类中,这些操作都要被完结。
- 一个类能够完结多个接口,一个接口能够被多个类完结
接口是一种特殊的类,一切的接口都是结构型为<<interface>>
的类。在UML中,接口的标明办法有三种: 第一种是接口的图标标明,第二种是接口的润饰标明,第三种是接口的结构型标签标明。
- 假如接口运用 结构型标签标明,完结联系线是一条结尾带有空心三角的虚线,箭头指向接口,虚线上能够加上结构型关键字《implement》。
- 假如接口运用图标标明,完结联系线则是一条实线,没有箭头,实线上也能够加上结构型关键字《implement》。
- 一个类运用接口,标明该类依靠该接口,用指向接口的一条虚线箭头标明,箭头上能够加上结构型关键字《use》。
事例: IElectricalEquipment接口界说了turnOn操作和turnoff操作,TV类和Player类均完结了该接口,即完结了turnOn操作和turnoff操作,RemoteControl类运用了IElectricalEquipment接口。
笼统类
笼统类指不具有实例的类,它一般作为父类,不创立实例方针。笼统类的子类能够实例化。
- 笼统类一般至少有一个笼统操作。
- 笼统类的作用是为其子类描绘它们的公共特点和行为。
- UML 选用斜体标明笼统类的称号,也能够运用 {abstract) 束缚来标明。
弥补代码:
// 界说一个 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 类完结了该接口。
类之间 6 种联系的耦合强度顺次增强
1 )依靠联系一耦合度最弱
2 )相相联系一耦合度其次弱
3 )聚合联系一耦合度一般
4 )组合联系一耦合度较高
5 )承继联系一耦合度高
6 )完结联系一耦合度最高
迪米特规律运用
类耦合对于方针之间协作完结特定功用是必要的,但它应该尽量被束缚在类的层次内,即层内耦合,层间耦合应该最小化。
为了束缚类间任意通讯,选用迪米特规律(最少常识准则)规划,指明在类操作中只允许将以下方针作为音讯方针,即没有直接联系的类之间不交互通讯,仅仅有直接联系类进行通讯。
- 当前方针本身
- 当前操作中作为参数的方针
- 当前方针的特点指向的方针
- 当前操作创立的方针
- 全局变量引用的方针
规划类图建模实践
- 规划类图建模是在剖析类图根底之上对体系剖析类图进行细化与完善规划,然后在规划层面描绘体系的静态结构。
- 在规划类图中除了具体界说各种类特点与办法外,还需界说类之间联系的规划束缚。
Power Designer 建模实践:雇员职位办理规划类图建模
ChatGPT4:
-
Person 类:
- 特点:
name
(String),sex
(char) - 办法:
getName()
回来 String,getSex()
回来 char - 这个类好像代表了具有根本特点如姓名和性别的一般人。
- 特点:
-
Employee 类(承继自 Person 类):
- 特点:
username
(String),password
(String) - 办法:
username
和password
的获取和设置办法,一个承受用户名和暗码并回来布尔值的login()
办法,以及重写的getName()
和getSex()
办法。 -
Employee
类承继自Person
类,这意味着每个Employee
都是Person
,但具有特定于雇员的额定特点和行为,如登录体系的凭证。
- 特点:
-
Post 类:
- 特点:
postname
(String) - 办法:
getPostname()
回来 String,setPostname()
承受一个 String,addPost()
回来一个布尔值。 - 这个类好像代表
Employee
能够持有的职位或职称。1..1
标明每个Employee
有且仅有一个Post
。
- 特点:
-
Department 类:
- 特点:
departmentname
(String) - 办法:
departmentname
的获取和设置办法,addDepartment()
回来布尔值。 - 代表安排中的一个部分。每个
Employee
与一个Department
相关,而一个Department
能够有多个雇员(1..*
联系)。
- 特点:
-
Power 类:
- 特点:
powername
(String) - 办法:
powername
的获取和设置办法。 - 代表与
Post
相关的权利或权限。每个Post
有且仅有一个Power
,标明一对一的联系。
- 特点:
-
Poweritem 类(承继自 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软件动态交互视图建模
软件动态交互视图用于描绘体系功用的方针之间动态交互行为。次序图和通讯图均归于动态交互模型图。
次序图
次序图也称序列图,它依照从上至下次序描绘方针之间的音讯交互,其意图是展现功用逻辑的规划完结。
- 次序图由一组方针及它们之间的音讯组成,着重音讯的先后时刻次序。
- 次序图也包含生命线、激活、片段等图形元素。
通讯图
通讯图是另一种类型的动态交互图,它用于表现方针之间的协作联系。通讯图由方针以及其相关组成,它着重方针间的衔接联系,方针之间音讯通讯次序运用序列号标明。
类操作
类操作(办法)是指类所能供应的服务或功用函数。类将一组操作函数作为服务供应给体系中的其他类拜访。
发现操作
- 可从次序图或通讯图的方针交互中发现类操作。次序图和通讯图中的每一条音讯,都有必要有方针方针的一个操作为其服务。
- 依据类的职责确认操作,如数据记录创立、读取、更新和删去操作。
类操作的标明
在 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中预界说了如下片段:
- opt选项片段
- alt条件片段
- loop循环片段
- para并行片段
(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为实体类方针。
UML软件状况机视图建模
状况机图是对体系中方针的状况改变逻辑进行建模,它描绘类方针随时刻改变的行为状况,以及方针受事情影响怎么进行状况变迁。
状况机图建模步骤:
- 发现方针状况
- 剖析方针变迁的事情与条件
- 树立方针状况图
事例:微波炉作业的状况机图
ChatGPT4:
状况:
- Waiting(等候):微波炉的初始状况,显现时刻,等候用户输入。
- Full Power(全功率):微波炉在全功率形式下作业,功率设置为600W。
- Half Power(半功率):微波炉在半功率形式下作业,功率设置为300W。
- Set Time(设置时刻):用户设置微波炉的作业时刻。
- Enabled(启用):微波炉门关闭,准备开端作业,显现“Ready”。
- Disabled(禁用):微波炉门敞开,不允许操作,显现“Waiting”。
- Operation(操作):微波炉开端作业。
转化和触发事情:
- 用户挑选全功率或半功率,微波炉进入相应的功率状况。
- 在任何功率状况下,设置时刻后,微波炉进入设置时刻的状况。
- 当时刻被设置后,假如微波炉门关闭,微波炉变为启用状况。
- 假如微波炉门翻开,微波炉将变为禁用状况。
- 从启用状况,开端操作将使微波炉进入操作状况并开端加热。
- 用户能够在任何时候取消操作,微波炉将回来到等候状况。
- 在操作完毕后,微波炉将完结加热过程并回来到等候状况。
针对如下电梯方针的状况机图模型,怎么编写其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 还允许将衔接器按如下方案衔接构件端口。
若有多个构件运用相同接口拜访另一构件接口, UML 允许将衔接器按如下方案衔接构件端口。
身份认证构件 (Authentication)端口与订单构件 (Orders) 端口均运用相同恳求接口(lCustomers)衔接客户构件(:Customers )端口的供应接口lCustomers。
托付衔接器是将构件的端口衔接到完结该行为的方针。它标明音讯抵达一个端口后,将被传递给内部方针方针进行处理。
事例:电子商务体系的构件图
布置图
- 布置图用于对体系的物理完结状况进行建模。
- 布置图用于标明软件构件怎么布置到硬件环境中,它显现体系中的不同构件在何处物理地运转,以及彼此之间怎么进行通讯。
节点
- 节点是指人工制品和构件在体系中布置的硬件设备及其运转环境。
- 节点之间经过通讯线路将衔接起来完结信息传输。
构件在节点中布置
构件需求在节点设备中运转。在建模时,需求将构件在节点中进行布置
事例:电子商务体系布置图
包图
- 在 UML 模型图中包用来对模型元素进行分组,简化 UML 图,使其更简单了解。
- 包图用于对模型自身安排进行建模,它是由一系列模型元素(类、用例等)构成的包所组成的模型,描绘包与包之间的联系。
包
UML 中包标明为左上方带有小矩形的矩形。包的称号选用字符串,简单名仅包含称号字符串,全束缚名则以本包地点的外围包的称号作为前缀。
包的可见性
包能够操控protected所包含的内部元素的可见性,即外部元素拜访包内元素的权限:
-
public
公共可见性: 对它地点包和内嵌包的方针可见,也对一切引入它的包及其子包中方针可见; -
- private
私有可见性: 只对它地点包中方针可见; -
# protected
保护可见性: 对它地点包和内嵌包中方针可见;
包的嵌套
- 包能够具有其他包,子包又能够具有自己的子包,然后构成嵌套结构。
- 包的嵌套能够明晰地表现模型元素之间的层次结构联系。
- 可是包的嵌套不宜过深,层数一般以 2到 3 层为宜
包图
- 包图描绘包与包之间的联系,可用于描绘软件体系的逻辑模型。
- 包与包之间能够存在依靠联系。两个包之间存在着依靠联系一般是指这两个包所包含的模型元素之间存在着一个或多个依靠联系。
- 包的依靠联系运用一根虚线箭线标明,箭头指向被依靠的包。依靠联系能够标上标签,在《》中包含依靠联系的类型。
事例:运用包图描绘体系的软件架构
针对如下股票出资剖析体系构件模型,剖析构件之间联系怎么规划?
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 )确认体系中的类
- 体系用户有办理员 (Administrator) 、图书办理员 (Librarian) 和借阅者(Borrower) 三个参与者,可将他们抽取为的人物实体类。
- 体系需存储图书信息,可抽取出Book类;需求存储借阅信息,可抽取出Loan类;需求存储预订信息,可抽取出Reservation类;这些类是体系中的首要事务实体类。
( 2 )确认类的特点
( 3 )确认类之间的联系,创立体系类图
体系动态模型规划
体系具体规划阶段,针对用例图中的每一个用例,考虑怎么经过方针之间的协作来完结用例的功用。选用次序图或通讯图对用例功用进行规划建模,选用状况机图对类的行为状况进行规划建模。
图书查找功用逻辑规划
图书借阅功用逻辑规划
图书偿还功用逻辑规划
Book方针的状况机图规划
Book 方针是图书办理体系中具有显着状况改变的方针,图书借阅事务都与Book方针状况有关。Book方针具有如下状况: 新书 (NewBook) 、可借阅预订(Available) 、被预订 (Reserved) 、被借阅 (Borrowed) 、被删去 (Deleted)。
Borrower方针的状况机图规划
Borrower方针也具有比较显着的状况,因此也选用状况机图对其建模。
Borrower 方针具 有 如下状况: 新建 (NewUser) 、未预订未借书 (NoLoanReserve) 、有预订 (HasReserve) 、有借书 (HasLoan) 、有预订有借书 (HasLoanReserve) 、被删去 (Deleted)。
静态结构的类图模型细化规划
-
Borrower类需求供应
- checkBorrower操作
- checkNumBooks操作
- addLoan操作
- deleteLoan操作
-
Book类需求供应
- searchBook操作
- checkBook操作
- setLoanStatus操作
-
Loan类需求供应
- addLoan操作
- deleteLoan操作
- checkOverdue操作
针对图书借阅办理体系如下构件,怎么规划体系布置图模型,并在布置图中给出布置联系和运转环境(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
咱们能够依照三层架构来安排这些构件:
-
标明层(经过Apache和JBoss保管): 包含一切的JSP页面,如
borrowBook.jsp
,returnBook.jsp
等。 -
事务逻辑层(运转在JBoss上): 包含操控和实体构件,如
borrowBook.java
,book.java
等。 -
数据层(运用PostgreSQL): 包含一切数据库表,如
BookInfo
,Loan
等。
现在,我将具体规划一个体系布置图模型来展现这些构件是怎么布置和彼此作用的:
- Apache Web Server: 保管一切的JSP页面。这些页面经过HTTP恳求与JBoss服务器通讯。
- JBoss Application Server: 处理来自Apache服务器的恳求,并运转Java操控和实体构件。JBoss能够布置这些Java构件,并供应必要的运转环境。
- PostgreSQL Database Server: 存储一切的数据库表,由JBoss服务器经过JDBC进行拜访和操作。
- Apache Web Server保管JSP页面,并将恳求转发给JBoss服务器。
- JBoss服务器处理事务逻辑,并与数据库服务器进行交互以存储或检索数据。
- PostgreSQL数据库服务器存储和办理数据,为事务逻辑层供应数据支撑。
一切这些组件都布置在Ubuntu操作体系上,保证体系兼容性和稳定性。