vlambda博客
学习文章列表

设计模式之MVC中的设计模式(连载中 12)

本篇介绍

在实际应用中,往往会按照场景同时使用多种设计模式。本篇介绍下MVC(模型,视图,控制器)模型中的控制模式,主要是模型中的观察者模式,视图中的组合模式和控制器中的策略模式。本篇重在介绍模式,因此略去了Swing和web相关的内容。最后也会用代码演示下具体实现。

MVC中设计模式介绍

以常用的音乐播放器为例,也可以分为三层,首先是直接和我们交互的视图界面,上面有播放,暂停,上一首,下一首等,这一层就可以看成是视图层,该层负责和用户交互。最底层就是最核心的数据层,用来存储各种歌曲信息,并对上提供接口,这就是模型。中间是控制层,将视图层接收到的请求解析成操作数据的方式,比如说将视图层接收到的指令翻译成数据库的增删改查(CRUD),并调用数据层的接口。
这三层需要做到各自独立,视图可以按需更换控制层,视图的变化也不需要修改模型。对于播放器来说,就是需要从UI视图的播放器切换成web的播放器,模型不需要任何修改。只需要做web的视图,并选择web对应的控制器即可。

这儿为了展示在View中的组合模式,模拟了swing中控件的管理。view可以选择控制器和model。这三个模块各自独立,做到了松耦合。

MVC设计模式代码演示

package com.company;

public interface View {
void show();
default void setController(Controller controller) {}
default void start() {}
default void stop() {}
default void next() {}
default void quit() {}
}

package com.company;

public interface Mp3Observer {
void update();
}

package com.company;

import java.util.ArrayList;
import java.util.List;

public class Mp3View implements View, Mp3Observer {

private List<View>  viewList = new ArrayList<View>();
private View button = new Mp3Button();
private View menu = new Mp3Menu();
private Model model;
private Controller controller;

public Mp3View(Model model) {
viewList.add(button);
viewList.add(menu);
this.model = model;
model.registerObserver(this);
}

@Override
public void show() {
System.out.println(this.getClass().getName() + " show");
}

@Override
public void update() {
viewList.forEach(view -> view.show());
}

@Override
public void setController(Controller controller) {
this.controller = controller;
}

@Override
public void quit() {
model.unregisterObserver(this);
}

@Override
public void start() {
controller.start();
}

@Override
public void stop() {
controller.stop();
}

@Override
public void next() {
controller.next();
}
}

package com.company;

public class Mp3Menu implements View{
@Override
public void show() {
System.out.println(this.getClass().getName() + " show");
}
}

package com.company;

public class Mp3Button implements View {

@Override
public void show() {
System.out.println(this.getClass().getName() + " show");
}
}

package com.company;

public interface Controller {
void start();
void stop();
void next();
}

package com.company;

public class Mp3Controller implements Controller {

private Model model;

public Mp3Controller(Model model) {
this.model = model;
}

@Override
public void start() {
model.start();
}

@Override
public void stop() {
model.stop();
}

@Override
public void next() {
model.next();
}
}

package com.company;

public interface Model {
void start();
void stop();
void next();
void registerObserver(Mp3Observer o);
void unregisterObserver(Mp3Observer o);
}

package com.company;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class Mp3Model implements Model {
private List<Mp3Observer> observerList = new ArrayList<Mp3Observer>();

public Mp3Model() {
}

@Override
public void start() {
System.out.println(this.getClass().getName() + " start");
}

@Override
public void stop() {
System.out.println(this.getClass().getName() + " stop");
}

@Override
public void next() {
System.out.println(this.getClass().getName() + " next");
notifyObservers();
}

@Override
public void registerObserver(Mp3Observer o) {
observerList.add(o);
}

@Override
public void unregisterObserver(Mp3Observer o) {
for (int i = 0; i < observerList.size(); ++i) {
if (Objects.equals(observerList.get(i), o)) {
observerList.remove(i);
break;
}
}
}

private void notifyObservers() {
observerList.forEach(observer -> observer.update());
}
}

package com.company;

public class Main {

public static void main(String[] args) {
Model model = new Mp3Model();
View view= new Mp3View(model);
Controller controller = new Mp3Controller(model);
view.setController(controller);
view.start();
view.next();
view.stop();
view.quit();
}
}

output:
com.company.Mp3Model start
com.company.Mp3Model next
com.company.Mp3Button show
com.company.Mp3Menu show
com.company.Mp3Model stop

这儿View中管理button和menu控件就是组合模式,View中设置controller就是策略模式,View中注册观察者就是观察者模式。 在View中,有一点不合理的地方就是为了省略控件操作,在View中添加了控件操作方法来模拟界面操作,实际中,这块应该是在界面中点击界面调用的。这块将模拟操作的方法设置成了default,这样或许可以将不合理地方稍微弱化一些。

本篇总结

本篇主要介绍了MVC中设计模式的应用,并且用代码简单模拟了下MVC的结构。在实际中,为了解决问题往往需要使用多种设计模式,不过使用设计模式后,会让结构十分整洁,编码起来也十分流畅。但需要注意的是,坚持奥坎姆剃刀原则,实现一个功能,能简单就简单,为了设计模式而使用设计模式也是没必要的。