在開發項目中採用 MVC (Model-View-Controller) 模式,核心收益在於徹底解耦業務邏輯層與表示層。擁有完全獨立的對象操作 UI,使維護更簡單、代碼復用極易。遵循「面向接口編程,而非面向實現編程」原則,將依賴降至最低,讓系統輕鬆應對需求變更。
構建一個 Windows 界面顯示汽車方向與速度,用戶可改變方向、加速、減速。未來需擴展支持皮卡、三輪車,甚至移植到 Intranet Web 界面。這正是 MVC 大顯身手的完美場景。
交互流程:用戶操作 View → View 委託 Controller → Controller 操作 Model 並更新 View → Model 狀態變更通知 View (觀察者模式) → View 刷新顯示。
public enum AbsoluteDirection { North = 0, East, South, West }
public enum RelativeDirection { Right, Left, Back }
public interface IVehicleControl
{
void RequestAccelerate(int amount);
void RequestDecelerate(int amount);
void RequestTurn(RelativeDirection direction);
void SetModel(IVehicleModel model);
void SetView(IVehicleView view);
}
public interface IVehicleModel
{
string Name { get; set; }
int Speed { get; set; }
int MaxSpeed { get; }
int MaxTurnSpeed { get; }
int MaxReverseSpeed { get; }
AbsoluteDirection Direction { get; set; }
void Accelerate(int amount);
void Decelerate(int amount);
void Turn(RelativeDirection direction);
// 觀察者模式:Model 通知 View 狀態變更
void AddObserver(IVehicleView view);
void RemoveObserver(IVehicleView view);
void NotifyObservers();
}
public interface IVehicleView
{
void DisableAcceleration(); void EnableAcceleration();
void DisableDeceleration(); void EnableDeceleration();
void DisableTurning(); void EnableTurning();
void Update(IVehicleModel model); // 觀察者回調
}
public abstract class Automobile : IVehicleModel
{
private readonly ArrayList _observers = new ArrayList();
private int _speed;
private readonly int _maxSpeed, _maxTurnSpeed, _maxReverseSpeed;
private AbsoluteDirection _direction = AbsoluteDirection.North;
private string _name;
protected Automobile(int maxSpeed, int maxTurnSpeed, int maxReverseSpeed, string name)
{
_maxSpeed = maxSpeed;
_maxTurnSpeed = maxTurnSpeed;
_maxReverseSpeed = maxReverseSpeed;
_name = name;
}
// 觀察者模式實現
public void AddObserver(IVehicleView view) => _observers.Add(view);
public void RemoveObserver(IVehicleView view) => _observers.Remove(view);
public void NotifyObservers()
{
foreach (IVehicleView view in _observers)
view.Update(this);
}
// 屬性實現
public string Name { get => _name; set => _name = value; }
public int Speed => _speed;
public int MaxSpeed => _maxSpeed;
public int MaxTurnSpeed => _maxTurnSpeed;
public int MaxReverseSpeed => _maxReverseSpeed;
public AbsoluteDirection Direction => _direction;
// 行為實現 (狀態變更後通知觀察者)
public void Turn(RelativeDirection dir)
{
_direction = dir switch
{
RelativeDirection.Right => (AbsoluteDirection)((int)(_direction + 1) % 4),
RelativeDirection.Left => (AbsoluteDirection)((int)(_direction + 3) % 4),
RelativeDirection.Back => (AbsoluteDirection)((int)(_direction + 2) % 4),
_ => AbsoluteDirection.North
};
NotifyObservers();
}
public void Accelerate(int amount)
{
_speed += amount;
if (_speed > _maxSpeed) _speed = _maxSpeed;
NotifyObservers();
}
public void Decelerate(int amount)
{
_speed -= amount;
if (_speed < _maxReverseSpeed) _speed = _maxReverseSpeed;
NotifyObservers();
}
}
// 運動車
public class ACME2000SportsCar : Automobile
{
public ACME2000SportsCar(string name) : base(250, 40, -20, name) { }
public ACME2000SportsCar(string name, int maxSpeed, int maxTurn, int maxRev)
: base(maxSpeed, maxTurn, maxRev, name) { }
}
// 貨車 - 僅需新增此類,零修改現有代碼
public class ACME2000Truck : Automobile
{
public ACME2000Truck(string name) : base(80, 25, -12, name) { }
}
public class AutomobileControl : IVehicleControl
{
private IVehicleModel _model;
private IVehicleView _view;
public AutomobileControl() { }
public AutomobileControl(IVehicleModel model, IVehicleView view)
{
SetModel(model); SetView(view);
}
public void SetModel(IVehicleModel model) => _model = model;
public void SetView(IVehicleView view) => _view = view;
public void RequestAccelerate(int amount)
{
_model?.Accelerate(amount);
UpdateViewState();
}
public void RequestDecelerate(int amount)
{
_model?.Decelerate(amount);
UpdateViewState();
}
public void RequestTurn(RelativeDirection dir)
{
_model?.Turn(dir);
UpdateViewState();
}
// 核心業務邏輯:根據 Model 狀態控制 View 可用性
private void UpdateViewState()
{
if (_view == null) return;
if (_model.Speed >= _model.MaxSpeed)
{ _view.DisableAcceleration(); _view.EnableDeceleration(); }
else if (_model.Speed <= _model.MaxReverseSpeed)
{ _view.DisableDeceleration(); _view.EnableAcceleration(); }
else
{ _view.EnableAcceleration(); _view.EnableDeceleration(); }
if (_model.Speed >= _model.MaxTurnSpeed)
_view.DisableTurning();
else
_view.EnableTurning();
}
}
public class AutoView : UserControl, IVehicleView
{
private IVehicleControl _control = new AutomobileControl();
private IVehicleModel _model = new ACME2000SportsCar("Speedy");
// UI 元素: btnAccelerate, btnDecelerate, btnLeft, btnRight, lblStatus, pBar...
public AutoView()
{
InitializeComponent();
WireUp(_control, _model);
}
public void WireUp(IVehicleControl control, IVehicleModel model)
{
// 解除舊綁定
if (_model != null) _model.RemoveObserver(this);
_model = model;
_control = control;
_control.SetModel(_model);
_control.SetView(this);
_model.AddObserver(this);
}
// 按鈕事件 -> 委託 Controller
private void btnAccelerate_Click(object sender, EventArgs e)
=> _control.RequestAccelerate(int.Parse(txtAmount.Text));
private void btnDecelerate_Click(object sender, EventArgs e)
=> _control.RequestDecelerate(int.Parse(txtAmount.Text));
private void btnLeft_Click(object sender, EventArgs e)
=> _control.RequestTurn(RelativeDirection.Left);
private void btnRight_Click(object sender, EventArgs e)
=> _control.RequestTurn(RelativeDirection.Right);
// 觀察者回調 -> 更新 UI
public void Update(IVehicleModel model) => UpdateInterface(model);
private void UpdateInterface(IVehicleModel auto)
{
lblStatus.Text = $"{auto.Name} heading {auto.Direction} at speed: {auto.Speed}";
pBar.Value = auto.Speed > 0
? auto.Speed * 100 / auto.MaxSpeed
: auto.Speed * 100 / auto.MaxReverseSpeed;
}
// IVehicleView 界面控制實現
public void DisableAcceleration() => btnAccelerate.Enabled = false;
public void EnableAcceleration() => btnAccelerate.Enabled = true;
public void DisableDeceleration() => btnDecelerate.Enabled = false;
public void EnableDeceleration() => btnDecelerate.Enabled = true;
public void DisableTurning() => btnLeft.Enabled = btnRight.Enabled = false;
public void EnableTurning() => btnLeft.Enabled = btnRight.Enabled = true;
}
// 僅新增類,AutoView 中一行代碼切換
private void btnBuildTruck_Click(object sender, EventArgs e)
{
autoView1.WireUp(new AutomobileControl(), new ACME2000Truck(txtName.Text));
}
public class SlowPokeControl : IVehicleControl
{
// ... 實現接口,RequestAccelerate/Decelerate 中限制 amount <= 5
}
// 使用新策略
autoView1.WireUp(new SlowPokeControl(), new ACME2000Truck("Slow Truck"));
僅需創建實現 IVehicleView 的 Web UserControl (ASP.NET / Blazor / Razor Pages),核心 Model、Controller 零修改復用。
MVC 模式通過接口隔離、觀察者模式解耦狀態通知、依賴注入式裝配,實現了極低耦合、高內聚的架構。本例展示了如何輕鬆應對:新增實體類型、替換控制策略、跨平台 UI 移植。下次項目啟動時,請記住 MVC —— 你不會後悔!