設計模式


前言

  以前做項目的時候並沒有想過用過采用什么樣的設計模式進行開發。唯一用過的模式也就是MVC的開發模式了。但是當初對MVC模式理解的也是很片面。為了提高程序的運行效率,或者是對程序進行更進一步的優化,合理的設計模式是十分重要的。

MVC模式

  

 來自百度百科

MVC 是一種使用 MVC(Model View Controller 模型-視圖-控制器)
    • Model(模型)表示應用程序核心(比如數據庫記錄列表)。
    • View(視圖)顯示數據(數據庫記錄)。
    • Controller(控制器)處理輸入(寫入數據庫記錄)。
MVC 模式同時提供了對 HTML、CSS 和 JavaScript 的完全控制。

Model

    (模型)是應用程序中用於處理應用程序數據邏輯的部分。
  通常模型對象負責在數據庫中存取數據。

View

  (視圖)是應用程序中處理數據顯示的部分。
   通常視圖是依據模型數據創建的。

Controller

    (控制器)是應用程序中處理用戶交互的部分。
  通常控制器負責從視圖讀取數據,控制用戶輸入,並向模型發送數據。
 
 其中最典型的MVC就是JSP + servlet + javaBean的模式。用javaEE做過網站的都知道,structs框架就是采用的MVC的設計模式。
 

簡單不能再簡單的mvc的例子

1.用戶請求 

......
<form action="LoginServlet" name="login" method="post">
    姓名:<input type="text" name="userName">
    密碼:<input type="text" name="password">
    <input type="submit" value="提交">
</form>
......

2.Model部分

......javaBean, 處理應用程序數據邏輯的部分
public class LoginService {
public LoginService(){}
public boolean checkLogin(String userName, String password){ //DAO層實現數據的查詢,根據數據庫中的信息進行對比判斷是否登錄成功 //用於登錄成功后可以調用GetMessage()得到最終VIEW中要顯示的數據。 } public List<Message> GetMessage(String userName){ //返回用戶的信息,存入Message實例中,並放入sessino中。 } }

3.Controler部分

......
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    public LoginServlet() {
        super();
    }
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session=request.getSession();
        ......
        判斷登錄是否成功
        ......
        
        ......
        通過Model的邏輯處理,得到View中要顯示的數據,並跳轉到相應的View
        ......
        response.sendRedirect("index.jsp");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        process(request,response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        process(request, response);
    }
}

4.View部分

......jsp頁面
<%
    ......
        通過session獲得Model產生的數據並顯示
    ......
%>
......

 

觀察者模式

   觀察者模式定義了一個一對多的依賴關系,讓一個或多個觀察者對象監察一個主題對象。這樣一個主題對象在狀態上的變化能夠通知所有的依賴於此對象的

那些觀察者對象,使這些觀察者對象能夠自動更新。

 java觀察者模式

實現觀察者模式

1.創建被觀察者類,它繼承自java.util.Observable類;
2.創建觀察者類,它實現java.util.Observer接口;
3.對於被觀察者類,
   添加它的觀察者:
   void addObserver(Observer o)
   addObserver()方法把觀察者對象添加到觀察者對象列表中。
 當被觀察事件發生時,執行:
   setChanged();
   notifyObservers();
 setChange()方法用來設置一個內部標志位注明數據發生了變化;

   notifyObservers()方法會去調用觀察者對象列表中所有的Observer的update()方法,通知它們數據發生了變化。
   只有在setChange()被調用后,notifyObservers()才會去調用update()。至於為什么可以看一下下面的源碼。

    /**
     * If {@code hasChanged()} returns {@code true}, calls the {@code update()}
     * method for every observer in the list of observers using null as the
     * argument. Afterwards, calls {@code clearChanged()}.
     * <p>
     * Equivalent to calling {@code notifyObservers(null)}.
     */
    public void notifyObservers() {
        notifyObservers(null);
    }

    /**
     * If {@code hasChanged()} returns {@code true}, calls the {@code update()}
     * method for every Observer in the list of observers using the specified
     * argument. Afterwards calls {@code clearChanged()}.
     *
     * @param data
     *            the argument passed to {@code update()}.
     */
    @SuppressWarnings("unchecked")
    public void notifyObservers(Object data) {
        int size = 0;
        Observer[] arrays = null;
        synchronized (this) {
            if (hasChanged()) {//如果變換了,arrays才不會為null
                clearChanged();
                size = observers.size();
                arrays = new Observer[size];
                observers.toArray(arrays);
            }
        }
        if (arrays != null) {
            for (Observer observer : arrays) {
                observer.update(this, data);
            }
        }
    }


4.對於觀察者類,實現Observer接口的唯一方法update
void update(Observable o, Object arg)
形參Object arg,對應一個由notifyObservers(Object arg);傳遞來的參數,當執行的是notifyObservers();時,arg為null。

觀察者模式舉例

   1.生產者充當被觀測的對象,生產者可以生產的水果如下。

class ProduceFruit extends Observable{
    private String[] msg = {"蘋果", "香蕉", "橘子"};
    
    private int fruitNum;
    
    public String[] getMsg() {
        return msg;
    }
    public int getFruitNum() {
        return fruitNum;
    }
    public void setFruitNum(int fruit, int fruitNum) {
        this.fruitNum = fruitNum;
        setChanged();
        notifyObservers(fruit);
    }
    
}

   2.多個消費者充當觀察者,每個消費者觀察不同的水果生產情況

class ConsumeFruit implements Observer{
    private String consumeMsg;
    
    @Override
    public void update(Observable o, Object arg) {
        ProduceFruit pf = (ProduceFruit)o;
        Integer index = (Integer)arg;
        if(consumeMsg.equals(pf.getMsg()[index])){
            //每種水果對應的不同的消費觀察者
            System.out.println(consumeMsg + "消費的數量 " + pf.getFruitNum());
        }
    }

    public ConsumeFruit(String consumeMsg) {
        super();
        this.consumeMsg = consumeMsg;
    }
}

  3.生產者(被觀察者)隨機生產水果,通知消費者(觀察者)進行消費

public class Main {
    public static void main(String[] args){
        ProduceFruit pf = new ProduceFruit();
        pf.addObserver(new ConsumeFruit("蘋果"));//觀察蘋果生產
        pf.addObserver(new ConsumeFruit("香蕉"));//觀察香蕉生產
        pf.addObserver(new ConsumeFruit("橘子"));//觀察橘子生產
        Random rd = new Random();
        for(int i=0; i<5; ++i){
            int fruit = Math.abs(rd.nextInt())%3;
            int fruitNum = Math.abs(rd.nextInt())%100;
            pf.setFruitNum(fruit, fruitNum);
        }
    
if(pf instanceof ProduceFruit) System.out.println(true);

if(pf.getClass().equals(ProduceFruit.class)) System.out.println(true);

     if(pf.getClass() == ProduceFruit.class) System.out.println(true);

    }
}

JDK中已經實現的一套觀察者模式

    最典型的就是Swing框架的JButton的實現。JButton繼承自AbstractButton,在AbstractButton中維護了一組監聽器,它們就扮演者被觀察的角色。而AbstractButton本身就是被觀察對象。監聽器ActionListener並不是依靠循環監聽去獲取按鈕何時被單擊,而是當按鈕被單擊時,通過AbstractButton的fireActionPerformed()方法回調ActionListener.actionPerformed()方法實現。基於這種結構,在應用程序開發時,只要簡單的實現ActionListerner接口(也就是Observer),並將其添加到按鈕的觀察者列表中,那么當單擊事件發生就可以自動促發監聽器的業務處理函數。

  1.親測一個小例子

class BtnListener implements ActionListener{
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("click");
    }
}

public class Main {
    public static void main(String[] args){
        JFrame p = new JFrame();
        JButton btn = new JButton("點擊我!");
        btn.addActionListener(new BtnListener());
        btn.setPreferredSize(new Dimension(200, 200));
        p.add(btn);
        p.pack();//調整此窗口的大小,以適合其子組件的首選大小和布局
        p.setVisible(true);
    }
}

  2.以下是AbstractButton中的一段處理代碼

protected void fireActionPerformed(ActionEvent event) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();
        ActionEvent e = null;
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length-2; i>=0; i-=2) {
            if (listeners[i]==ActionListener.class) {
                // Lazily create the event:
                if (e == null) {
                      String actionCommand = event.getActionCommand();
                      if(actionCommand == null) {
                         actionCommand = getActionCommand();
                      }
                      e = new ActionEvent(AbstractButton.this,
                                          ActionEvent.ACTION_PERFORMED,
                                          actionCommand,
                                          event.getWhen(),
                                          event.getModifiers());
                }
                ((ActionListener)listeners[i+1]).actionPerformed(e);
            }
        }
    }

   寫到這里,不得不說一下MVC模式和觀察者模式結合的小例子。Long long ago,我用C寫了一個貪吃蛇的小游戲,沒有什么技術含量,當時並沒有考慮用什么樣的設計模式去寫,而是想怎么寫就怎么寫,最終完成了。我知道這樣的寫法非常的不好,尤其是出現BUG的時候,調試起來是非常的麻煩。基於上面的兩個設計模式,看一下“貪吃蛇”新的設計思路。

“貪吃蛇”設計模式

  1.Model,並充當被觀察者

class SnakeModel extends Observable implements Runnable{
    //......
    //Snake狀態信息,以及狀態變化的方法。
    //......
    @Override
    public void run() {
        //通過線程實現 模型的狀態變化。
        //每次的狀態變化,Model通知View數據已經更新,請更新視圖。
        //......
    }
}

  2.View,並充當觀察者

class SnakeView extends JFrame implements Observer{
    private void initView(){
        //初始化視圖
        //......
    }
    @Override
    public void update(Observable o, Object arg) {
        SnakeModel mode = (SnakeModel)o;//獲取被監控的模型
        //根據模型中Snake狀態信息,開始更新Snake的視圖
        //......
    }
}

  3.Controler,將Model和View結合起來

class SnakeControl extends KeyAdapter{
    private SnakeModel model;//待控制的貪吃蛇的模型對象
    private SnakeView view;//貪吃蛇的視圖對象
    private void initControl(){
        //創建SnakeModel
        //創建SnakeView
        model.addObserver(view);//為模型添加視圖(被觀察者添加觀察者)
        view.addKeyListener(this);//為視圖添加鍵盤的事件處理器
    }
    @Override
    public void keyPressed(KeyEvent e) {
        super.keyPressed(e);
        int keyCode = e.getKeyCode();
        //根據不同的按鍵,通過Model設置Snake新的狀態
    }
}

  最后通過主函數,創建SnakeControl對象就可以是整個程序跑起來了。設計方法很重要,最后就是一步一步的完善了。關於設計模式就先寫到這里了,過幾天再完善,要考6級了,先復習...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM