本次实验属于模仿型实验,通过本次实验学生将掌握以下内容:
1、掌握面向对象程序设计中类与类之间的关系以及对应的UML类图;
2、理解面向对象程序设计原则。
[实验任务一]:UML复习
阅读教材第一章复习UML,回答下述问题:
Q:面向对象程序设计中类与类的关系都有哪几种?分别用类图实例说明。
A:1.关联关系:一种结构化的关系,用于表示一类对象与另一类对象之间有联系,如登录和注册按钮。
1.1双联关系:默认情况下,关联式双向的,有两个角色名。如顾客购买商品并拥有商品。
1.2单联关系:类关联关系也可以是单项的,只有一个角色名。如顾客拥有地址。
1.3自关联关系:在系统中可能存在一些类的属性对象类型为该类本身。如一个节点类的成员又是节点对象。
1.4多重关联关系:表示一个类的对象与另一个类的对象连接的个数。如一个界面可以拥有零个或多个按钮,但是一个按钮只能属于一个界面。
1.5聚合关系:表示一个整体和部分的关系,成员类是整体类的一部分,即成员对象是整体对象的一部分,成员对象可以脱离对象独立存在。如汽车发动机是汽车的组成部分,但是汽车发动机可以独立存在。
1.6组合关系:表示类之间整体和部分的关系,但是组合关系中部分和整体具有统一的生存周期。如人的头没了,那嘴巴也没了。
-
依赖关系:特定事物的改变有可能会影响到使用该事物的其他事务,在需要表示一个事物使用另一个事物时的依赖关系。如驾驶员开车。
-
泛化关系:用于描述父类(基类、超类)和子类(派生类)之间的关系。
4.接口与实现关系:类实现接口,类中的操作实现了接口中所声明的操作。
[实验任务二]:单一职责原则
登录模块在实际项目开发中很常见,请按照教材28页(PPT49页)利用单一职责原则重构后的类图实现这一模块。
实验要求:
- 提交源代码和对应的数据库文件(注意将此模块保存,以备以后使用);
数据库文件
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `login`
-- ----------------------------
DROP TABLE IF EXISTS `login`;
CREATE TABLE `login` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userName` varchar(255) NOT NULL,
`userPassword` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of login
-- ----------------------------
INSERT INTO `login` VALUES ('1', 'admin', '123456');
DBUtil.java文件
package login;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DBUtil {
public static final String url="jdbc:mysql://localhost:3306/db1";//URL
public static final String user="root";//用户名
public static final String password="123456";//密码
/**
* 连接数据库
* @return
*/
public static Connection getConnection(){
Connection conn=null;
try {
Class.forName("com.mysql.jdbc.Driver");//加载数据库驱动
conn=DriverManager.getConnection(url, user, password);
System.out.println("数据库连接成功!");
}catch(Exception e) {
e.printStackTrace();
}
return conn;
}
/**
* 关闭数据库
*/
public static void close(Connection conn,PreparedStatement pstm) {
System.out.println("关闭SQL(conn,pstm)");
if(pstm!=null) {
try {
pstm.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
conn.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Connection conn,PreparedStatement pstm,ResultSet rs) {
System.out.println("关闭SQL(conn,pstm,rs)");
if(pstm!=null) {
try {
pstm.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
conn.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
if(rs!=null) {
try {
rs.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
}
// public static void main(String[] args) {
// getConnection();
// }
}
LoginFrom.java
package login;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
@SuppressWarnings("serial")
public class LoginForm extends JFrame implements ActionListener {// 负责页面显示
JTextField text_name = new JTextField();
JPasswordField text_password = new JPasswordField();
private boolean login=false;
public void init() {// 用于初始化按钮、文本框等界面控件
// 在init中实例化JFrame类的对象
JFrame frame = new JFrame();
// 设置窗体对象的属性值
frame.setTitle("登录");// 设置窗体标题
frame.setSize(400, 250);// 设置窗体大小,只对顶层容器生效
frame.setDefaultCloseOperation(3);// 设置窗体关闭操作,3表示关闭窗体退出程序
frame.setLocationRelativeTo(null);// 设置窗体相对于另一组间的居中位置,参数null表示窗体相对于屏幕的中央位置
frame.setResizable(false);// 禁止调整窗体大小
frame.setFont(new Font("宋体", Font.PLAIN, 14));// 设置字体,显示格式正常,大小
// 实例化FlowLayout流式布局类的对象,指定对齐方式为居中对齐组件之间的间隔为10个像素
FlowLayout fl = new FlowLayout(FlowLayout.CENTER, 10, 10);
// 实例化流式布局类的对象
frame.setLayout(fl);
// 实例化JLabel标签对象,该对象显示“账号”
JLabel labname = new JLabel("Name:");
labname.setFont(new Font("宋体", Font.PLAIN, 14));
// 将labname标签添加到窗体上
frame.add(labname);
// 实例化JTextField标签对象化
Dimension dim1 = new Dimension(300, 30);
text_name.setPreferredSize(dim1);// 设置除顶级容器组件以外其他组件的大小
// 将textName标签添加到窗体上
frame.add(text_name);
// 实例化JLabel标签对象,该对象显示“密码”
JLabel labpass = new JLabel("Password:");
labpass.setFont(new Font("宋体", Font.PLAIN, 14));
// 将labpass添加到窗体上
frame.add(labpass);
// 设置大小
text_password.setPreferredSize(dim1);
// 添加到窗体
frame.add(text_password);
// 实例化JButton组件
JButton button1 = new JButton();
// 设置按键的显示内容
Dimension dim2 = new Dimension(100, 30);
button1.setText("登录");
button1.setFont(new Font("宋体", Font.PLAIN, 14));
// 设置按键大小
button1.setSize(dim2);
button1.addActionListener(new ActionListener() {// 给按钮添加事件接收器
@Override
public void actionPerformed(ActionEvent e) {// 接受到事件后,进行下面的处理
validate();
}
});
frame.add(button1);
frame.setVisible(true);// 窗体可见,一定要放在所有组件加入窗体后
}
public void display() {// 用于向界面容器中增加页面控件并显示窗口
int i = 3;// 3次登录机会
Dimension dim3 = new Dimension(300, 30);
// 生成新界面
javax.swing.JFrame login2 = new javax.swing.JFrame();
login2.setSize(400, 200);
login2.setDefaultCloseOperation(3);
login2.setLocationRelativeTo(null);
login2.setFont(new Font("宋体", Font.PLAIN, 14)); // 宋体,正常风格,14号字体
// 创建组件
javax.swing.JPanel jp1 = new JPanel();
javax.swing.JPanel jp2 = new JPanel();
if(login==true) {
JLabel message = new JLabel("登陆成功!");
message.setFont(new Font("宋体", Font.PLAIN, 14)); // 宋体,正常风格,14号字体
message.setPreferredSize(dim3);
jp1.add(message);
login2.add(jp1, BorderLayout.CENTER);
login2.setResizable(false);
login2.setVisible(true);
}else {
if (i >= 2) {
JLabel message = new JLabel("账号或密码错误,您今天还有" + (i - 1) + "次机会");
message.setFont(new Font("宋体", Font.PLAIN, 14)); // 宋体,正常风格,14号字体
message.setPreferredSize(dim3);
// 将textName标签添加到窗体上
jp1.add(message);
login2.add(jp1, BorderLayout.CENTER);
JButton close = new JButton("确定");
close.setFont(new Font("宋体", Font.PLAIN, 14));
// 设置按键大小
close.setSize(dim3);
jp2.add(close);
login2.add(jp2, BorderLayout.SOUTH);
i--;// 次数减少
close.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
login2.dispose();
}
});
login2.setResizable(false);
login2.setVisible(true);
}
else if (i == 1) {
JLabel message = new JLabel("账号已锁定,请明天再试");
message.setFont(new Font("宋体", Font.PLAIN, 14)); // 宋体,正常风格,14号字体
message.setPreferredSize(dim3);
// 将textName标签添加到窗体上
jp1.add(message);
login2.add(jp1, BorderLayout.CENTER);
JButton close = new JButton("确定");
close.setFont(new Font("宋体", Font.PLAIN, 14));
// 设置按键大小
close.setSize(dim3);
jp2.add(close);
login2.add(jp2, BorderLayout.SOUTH);
close.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
login2.dispose();
}
});
login2.setResizable(false);
login2.setVisible(true);
}
}
}
public void validate() {// 供登录按钮的事件处理方法调用,用于调用与数据库相关的方法完成登录处理,如果登录成功则进入主页面,否则提示错误信息
if (UserDAO.findUser(text_name, text_password)) {
System.out.println("登录成功");
login=true;
display();
} else {
System.out.println("登录失败");
login=false;
display();
}
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
Mainclass.java
package login;
public class MainClass {//负责启动系统
public static void main(String[] args) {
//在主函数中,实例化Login类的对象,调用初始化界面的方法
LoginForm login = new LoginForm();
login.init();
}
}
UserDAO
package login;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class UserDAO {//负责用户表的增删改查操作,它封装了对用户表的全部操作代码,登录本质上是一个查询用户表的操作
//登录的查询操作
@SuppressWarnings("deprecation")
public static boolean findUser(javax.swing.JTextField userName,
javax.swing.JPasswordField userPassword) {//用于根据用户名和密码查询数据库中是否存在该用户,如果存在则返回true,否则返回false,该方法需要调用getConnection()方法连接数据库,并供validate()方法调用
Connection conn=null;
PreparedStatement pstm=null;
ResultSet rs=null;
try {
conn=DBUtil.getConnection();
String sql="select * from login where userName=? and userPassword=?";
System.out.println(sql);
pstm=conn.prepareStatement(sql);
pstm.setString(1, userName.getText());
pstm.setString(2, userPassword.getText());
rs=pstm.executeQuery();
while(rs.next()) {
System.out.println("userName:"+rs.getString("userName")+",userPassword:"+rs.getString("userPassword"));
return true;
}
}catch(Exception e) {
e.printStackTrace();
}finally {
//SQL执行完成后释放相关资源
DBUtil.close(conn,pstm,rs);
}
return false;
}
}
2.注意编程规范。
[实验任务三]:依赖倒转原则与合成复用原则
在一画图软件中提供了多种大小不同的画笔,并且可以给画笔指定不同的颜色,某设计人员对画笔进行了如上图所示的设计。通过分析,可以发现增加画笔的种类和颜色会使得系统中类的数目急剧增加,请根据合成复用原则和依赖倒转原则对上述设计进行重构。
实验要求:
- 提交源代码;
型号抽象类
public abstract class Size {
public abstract void sizePen();
}
具体型号类
public class SmallPen extends Size{
//小型
public void sizePen() {
System.out.println("小型");
}
}
public class MiddlePen extends Size{
//中型
public void sizePen() {
System.out.println("中型");
}
}
public class BigPen extends Size{
//大型
public void sizePen() {
System.out.println("大型");
}
}
颜色抽象类
public abstract class Color {
public abstract void colorPen();
}
具体颜色类
public class GreenPen extends Color{
public void colorPen() {
System.out.println("绿色");
}
}
public class RedPen extends Color{
public void colorPen() {
System.out.println("红色");
}
}
钢笔
public class Pen {
//钢笔
private Size size;
private Color color;
public Size getSize() {
return size;
}
public void setSize(Size size) {
this.size = size;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
聚合钢笔
public class MianClass {
public static void main(String[] args) {
//颜色大小随意组合
Pen pen=new Pen();
//组合小型红色钢笔
pen.setSize(new SmallPen());
pen.setColor(new RedPen());
//组合大型绿色钢笔
pen.setSize(new BigPen());
pen.setColor(new GreenPen());
}
}
2.画出重构后的类图。