课程名称:《软件体系结构与设计模式》
实验项目名称:基于MVC模式下的二手车拍卖平台设计
实验内容 按下列要求编写程序并上机调试运行:
- 拍卖系统要又三个显示界面,分别是车体图片,文字描述和出价区。
- 将系统分解成MVC三个类进行方法设计。
- M和V必须观察者模式进行设计。
- 使用SWING进行界面设计。
- 按钮点击,必须更新车型和图片,并用时间驱动结构进行设计。
- 额外要求:要求报价必须只能提高,不等减少,如减少弹出警告窗口。
代码15元1份,有需要联系+qq2421442475
以下写类图和代码
类图:
分析与代码展示:
其中,CarGUI提供用户输入界面,代表用户;CarModel为MVC体系结构中的模型部分(Model);BitView和SearchView代表视图部分(View);而Controller为控制器部分。
用户通过使用CarGUI图形界面在的列表选择待拍卖的车,单击“Search”按钮,获取车的图片和文字说明;然后输入竞拍价,单击“Bit”按钮,竞拍价将显示在拍卖价格显示区域上;若下次的拍卖价格比这次的价格低,则会弹出警告窗口消息框并会在拍卖价格显示区域上显示一条信息:“Bit price for”+CarName+“:”+“illegal bit price”。
程序运行结果图如下图所示。
图1
图2
图3
图4
Observer类
public interface Observer {
public void update(Observable subject);
}
Observable类
public interface Observable {
public void register(Observer obs);
public void notifyObservers();
}
在该设计类图中设计了两个接口类:Observable与Observer,Model类实现Observable接口,而View类实现Observer接口。也就是说Model对象是被观察者而View对象是观察者。根据观察者机制,被观察者类应该包含registerObserver( )、notifyObservers( )方法,其功能是在被观察者对象中利用registerObserver( )加入被观察者对象,并且当被观察者的数据或者状态有了改变的时候,利用notifyObservers( )方法通知观察者。此时,观察者类中的update( )方法将自动运行,达到及时更新观察者的目的。
CarModel类
import javax.swing.*;
import java.util.ArrayList;
public class CarModel implements Observable{
private ArrayList<Observer> observers;
private String carName;
private String bitPrice;
private ImageIcon icon;
String [] carSelected = {"Honda Accord"," "," ","Made in 2005, used by the Department of defense.","Mileage: 60,000 miles.","5-speed automatic (25 city/36 highway) transmission?"," "," "," "," "};
String [] car2Selected = {"Honda Civic"," "," ","Made in 2006,used by the New York State government ","Mileage 40,4000 miles.","5-speed manual (25 city/36 highway) transmission?","140-hp, 1.8-Liter, 16-Valve SOHC i-VTEC? 4-cylinder engine"," "};
String [] car3Selected = {"Toyota Camry"," "," ","Made in 2003, used by the Washington State government","Mileage: 100,000 miles.","5-speed automatic (25 city/36 highway) transmission?","140-hp, 1.8-Liter, 16-Valve SOHC i-VTEC? 4-cylinder engine"," "};
String [] car4Selected = {"Toyota Corolla"," "," ","Made in 2002, used by the Washington State government","Mileage: 120,000 miles.","5-speed automatic (25 city/36 highway) transmission?", "140-hp, 1.8-Liter, 16-Valve SOHC i-VTEC? 4-cylinder engine"," "};
public CarModel() {
observers = new ArrayList<Observer>();
}
public String getCarName() {
return carName;
}
public String getBitPrice() {
return bitPrice;
}
public void setCarName(String carName) {
this.carName = carName;
notifyObservers();
}
public void setBitPrice(String bitPrice) {
this.bitPrice = bitPrice;
notifyObservers();
}
public ImageIcon getImage() {
return this.icon;
}
public void setImage(String file) {
this.icon = new ImageIcon(file);
notifyObservers();
}
@Override
public void register(Observer obs) {
observers.add(obs);
}
@Override
public void notifyObservers() {
for (int i = 0; i < observers.size(); i++) {
observers.get(i).update(this);
}
}
}
BitView类
import javax.swing.*;
public class BitView implements Observer{
private final CarModel cm;
private final CarGUI cg;
public BitView(CarModel cm,CarGUI cg) {
this.cm = cm;
this.cg=cg;
}
@Override
public void update(Observable subject) {
if ( subject == cm){
String name= cm.getCarName();
String p = cm.getBitPrice();
String text=" Bit price for "+ name + " : "+ p;
ImageIcon imIcon = cm.getImage();
cg.setIcon(imIcon);//更新拍卖车图片区域
cg.showPrice(text);//更新拍卖价格显示区域
}
}
}
SearchView类
import javax.swing.*;
public class SearchView implements Observer {
private final CarModel cm;
private final CarGUI cg;
public SearchView(CarModel cm,CarGUI cg) {
this.cm = cm;
this.cg=cg;
}
@Override
public void update(Observable subject) {
if ( subject == cm){
ImageIcon imIcon = cm.getImage();
cg.setIcon(imIcon);
}
}
}
其中,CarGUI提供了用户输入界面,代表用户。注意,在类CarGUI中,创建与初始化了CarModel、SearchView和BitView对象,并且调用CarModel中的register(Observer obs),分别将SearchView和BitView的对象注册到该CarModel对象。
①箱子布局管理,主要是Swing包中的Box来进行盒子布局,包括两种箱子:一种是水平箱子、一种是垂直箱子。构造方法如下:
Box box=Box.createHorizontalBox()//创建水平箱子对象
Box box=Box.createVertiaclBox()//创建垂直箱子对象
箱子创建好后,用add()把组件添加到箱子里面
②设置控件间隔的方法
Box.createHorizontalStrut(int width)//设置左右两个组件的宽度
Box.createVerticalStrut(int height)//设置上下两个组件的距离
CarGUI类
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class CarGUI {
private static CarModel carModel;
private static BitView bitView;
private static SearchView searchView;
private JComboBox carSelector;
String [] carNameList = {"Honda Accord-2005","Honda Civic-2006","Toyota Camry-2003","Toyota Corolla-2002"};
String [] carSelected = {"Honda Accord"," "," ","Made in 2005, used by the Department of defense.","Mileage: 60,000 miles.","5-speed automatic (25 city/36 highway) transmission?"," "};
JFrame frame = new JFrame("MVC pattern 二手车拍卖");
JTextArea bitShownText = new JTextArea("Bit price for each car will be shown here",4,20);
JTextField bitInputText = new JTextField("Offer your bit price",10);
JLabel imgLabel = new JLabel();
JList textList = new JList<>(carSelected);
Icon icon=new ImageIcon("images\\Honda Accord-2005.jpg");
//组装视图的函数
public void init(){
//注册被观察者与观察者
carModel = new CarModel();
bitView= new BitView(carModel,this);
searchView = new SearchView(carModel, this);
carModel.register(bitView);
carModel.register(searchView);
//窗口大小
frame.setBounds(200,200,500,300);
//组装顶部相关元素
Box pBox = Box.createVerticalBox();
//组装车的类型和下拉框
Box uBox = Box.createHorizontalBox();
JLabel carlbl = new JLabel("Cars:");
carSelector = new JComboBox<>(carNameList);
carSelector.setMaximumRowCount(4);
uBox.add(Box.createHorizontalStrut(50));
uBox.add(carlbl);
uBox.add(Box.createHorizontalStrut(10));
uBox.add(carSelector);
uBox.add(Box.createHorizontalStrut(10));
//组装搜索和退出按钮
Box btn2Box = Box.createHorizontalBox();
JButton searchBtn = new JButton("Search");
JButton exitBtn = new JButton("Exit");
btn2Box.add(Box.createHorizontalStrut(5));
btn2Box.add(searchBtn);
btn2Box.add(Box.createHorizontalStrut(5));
btn2Box.add(exitBtn);
btn2Box.add(Box.createHorizontalStrut(100));
//组装Bit和文本框
Box btn1Box = Box.createHorizontalBox();
JButton bitButton = new JButton("Bit");
bitInputText.setBackground(Color.green);
btn1Box.add(Box.createHorizontalStrut(5));
btn1Box.add(bitButton);
btn1Box.add(Box.createHorizontalStrut(20));
btn1Box.add(bitInputText);
btn1Box.add(Box.createHorizontalStrut(30));
//组装左上部分
pBox.add(Box.createVerticalStrut(10));
pBox.add(uBox);
pBox.add(Box.createVerticalStrut(20));
pBox.add(btn2Box);
pBox.add(Box.createVerticalStrut(20));
pBox.add(btn1Box);
pBox.add(Box.createVerticalStrut(20));
//组装右上文本域
JScrollPane bitInfo = new JScrollPane(bitShownText);//拍卖价格显示区域
//组装顶部
Box topBox = Box.createHorizontalBox();
topBox.add(pBox);
topBox.add(bitInfo);
//组装左下
imgLabel.setIcon(icon);
JScrollPane imagePane = new JScrollPane(imgLabel);
//组装右下
JScrollPane bigSplitPane = new JScrollPane(textList);
//组装底部相关元素
Box baseBox= Box.createHorizontalBox();
baseBox.add(imagePane);
baseBox.add(bigSplitPane);
//组装整体
Box holeBOX = Box.createVerticalBox();
holeBOX.add(topBox);
holeBOX.add(baseBox);
//添加监听器
Controller buttonTeam = new Controller(this,carModel);
searchBtn.addActionListener(buttonTeam);
exitBtn.addActionListener(buttonTeam);
bitButton.addActionListener(buttonTeam);
frame.add(holeBOX);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();//调整此窗口的大小,以适合其子组件的首选大小和布局
frame.setVisible(true);
}
public String getBitPrice(){
return bitInputText.getText();
}
public String getCarName(){
return carSelector.getSelectedItem().toString();// getSelectedItem():获得所选项的内容。
}
public void showPrice(String text){
bitShownText.setText(text);
}
public void setIcon(ImageIcon icon) {
imgLabel.setIcon(icon);
imgLabel.validate();
}
public void setData(String[] name) {
textList.setListData(name);//更新文字信息
}
}
类CarModel封装了所有关于二手车拍卖的核心数据和提供给类Contoller和类SerachView、BitView调用的方法,该类保持了与其他三个类的高度的独立性。这里Conroller类实现了ActionListener接口。 在负责用户输人的类CarGUI中,所有的按钮Search 与Bit 都添加了Controller的对象。这样,当一个按钮对象被按下时所产生的事件触发了Controller对象的actionPerformed方法。在该方法中,将根据用户输入更新CarModel对象,然后在Controller类中,调用CarModel中的notifyObservers方法(此处为了节省代码量,在CarModel做了其他的处理,其效果是一样的)。而在notifyObservers方法中,则直接调用了SerachView和BitView中的update方法,实现了自动对被拍卖车的图片、文字信息以及拍卖价格的显示。
Controller类
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Controller implements ActionListener{
private final CarGUI cg;
private final CarModel cm;
private int preprice = 0;
private int preprice1 = 0;
private int preprice2 = 0;
private int preprice3 = 0;
public Controller(CarGUI cg, CarModel cm) {
this.cg = cg;
this.cm = cm;
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Search")) {
String text3 = cg.getCarName();
String text=" Bit price for each car will be shown here";
switch (text3) {
case "Honda Accord-2005":
cm.setImage("images\\Honda Accord-2005.jpg");
cg.setData(cm.carSelected);
cg.showPrice(text);
break;
case "Honda Civic-2006":
cm.setImage("images\\Honda Civic-2006.jpg");
cg.setData(cm.car2Selected);
cg.showPrice(text);
break;
case "Toyota Camry-2003":
cm.setImage("images\\Toyota Camry-2003.jpg");
cg.setData(cm.car3Selected);
cg.showPrice(text);
break;
case "Toyota Corolla-2002":
cm.setImage("images\\Toyota Corolla-2002.jpg");
cg.setData(cm.car4Selected);
cg.showPrice(text);
break;
}
}
if (e.getActionCommand().equals("Bit")) {
String text = cg.getBitPrice();
String text2 = cg.getCarName();
String text4=" Bit price for "+ text2 + " : "+ " illegal bit price ";
if (text2.equals("Honda Accord-2005")){
if(Integer.parseInt(text) > preprice){
preprice = Integer.parseInt(text);
cm.setImage("images\\Honda Accord-2005.jpg");
cg.setData(cm.carSelected);
cm.setCarName(text2);
cm.setBitPrice(text);
}else {
cg.showPrice(text4);
JOptionPane.showMessageDialog(null,"竞拍价格比上次低!","提示",JOptionPane.WARNING_MESSAGE);
}
}
if (text2.equals("Honda Civic-2006")){
if(Integer.parseInt(text) > preprice1){
preprice1 = Integer.parseInt(text);
cm.setImage("images\\Honda Civic-2006.jpg");
cg.setData(cm.car2Selected);
cm.setCarName(text2);
cm.setBitPrice(text);
}else {
cg.showPrice(text4);
JOptionPane.showMessageDialog(null,"竞拍价格比上次低!","提示",JOptionPane.WARNING_MESSAGE);
}
}
if (text2.equals("Toyota Camry-2003")){
if(Integer.parseInt(text) > preprice2){
preprice2 = Integer.parseInt(text);
cm.setImage("images\\Toyota Camry-2003.jpg");
cg.setData(cm.car3Selected);
cm.setCarName(text2);
cm.setBitPrice(text);
}else {
cg.showPrice(text4);
JOptionPane.showMessageDialog(null,"竞拍价格比上次低!","提示",JOptionPane.WARNING_MESSAGE);
}
}
if (text2.equals("Toyota Corolla-2002")){
if(Integer.parseInt(text) > preprice3){
preprice3 = Integer.parseInt(text);
cm.setImage("images\\Toyota Corolla-2002.jpg");
cg.setData(cm.car4Selected);
cm.setCarName(text2);
cm.setBitPrice(text);
}else {
cg.showPrice(text4);
JOptionPane.showMessageDialog(null,"竞拍价格比上次低!","提示",JOptionPane.WARNING_MESSAGE);
}
}
}
if (e.getActionCommand().equals("Exit")) {
System.exit(0);
}
}
}