国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

用Visual C#實現MVC模式的簡要方法

2024-07-21 02:29:55
字體:
來源:轉載
供稿:網友
  在我們的開發項目中使用mvc(model-view-control)模式的益處是,可以完全降低業務層和應用表示層的相互影響。此外,我們會有完全獨立的對象來操作表示層。mvc在我們項目中提供的這種對象和層之間的獨立,將使我們的維護變得更簡單使我們的代碼重用變得很容易(下面你將看到)。

  作為一般的習慣,我們知道我們希望保持最低的對象間的依賴,這樣變化能夠很容易的得到滿足,而且我們可以重復使用我們辛辛苦苦寫的代碼。為了達到這個目的我們將遵循一般的原則“對接口編成,而不是對類”來使用mvc模式。

  我們的使命,如果我們選擇接受它...

  我們被委任構建一個acme 2000 sports car項目,我們的任務是做一個簡單的windows畫面來顯示汽車的方向和速度,使終端用戶能夠改變方向,加速或是減速。當然將會有范圍的擴展。

  在acme已經有了傳言,如果我們的項目成功,我們最終還要為acme 2 pickup truck 和acme 1 tricycle開發一個相似的接口。作為開發人員,我們也知道acme管理團隊最終將問“這樣是很棒的,我們能夠在我們的intranet上看到它?”所有的這些浮現在腦海中,我們想交付一個產品,使它能夠容易的升級以便能夠保證將來我們能夠有飯吃。

  所以,同時我們決定“這是使用mvc的一個絕好情形”

  我們的構架概要

  現在我們知道我們要使用mvc,我們需要指出它的本質。通過我們的試驗得出mvc的三個部分:model,control和view。在我們的系統中,model就是我們的汽車,view就是我們的畫面,control將這兩個部分聯系起來。

  為了改變model(我們的acme 2000 sports car),我們需要使用control。我們的control將會產生給model(我們的acme 2000 sports car)的請求,和更新view,view就是我們的畫面(ui)。

  這看起來很簡單,但是這里產生了第一個要解決的問題:當終端用戶想做一個對acme 2000 sports car一個改變將會發生什么,比如說加速或是轉向?他們將通過view(our windows form)用control來提出一個變化的申請。

  現在我們就剩下一個未解決問題了。如果view沒有必要的信息來顯示model的狀態怎么辦?我們需要再在我們的圖中加入一個箭頭:view將能申請model的狀態以便得到它要顯示的相關狀態信息。

  最后,我們的最終用戶(司機)將會和我們的acme vehicle control系統通過view來交互。如果他們想發出一個改變系統的申請,比如提高一點加速度,申請將會從view開始發出由control處理。

  control將會向model申請改變并將必要的變化反映在view上。比如,如果一個蠻橫的司機對acme 2000 sports car做了一個"floor it"申請,而現在行駛的太快不能轉向,那么control將會拒絕這個申請并在view中通知,這樣就防止了在交通擁擠是發生悲慘的連環相撞。

  model (the acme 2000 sports car) 將通知view 它的速度已經提高,而view也將做適當的更新。

  綜上,這就是我們將構建的概要:

  開始

  作為總是想的遠一點的開發人員,我們想讓我們的系統有一個長久并且良好的生命周期。這就是說能夠進可能的準備好滿足acme的很多變化。為了做到這一點,我們知道要遵循兩條原則...“保證你的類低耦合”,要達到這個目標,還要“對接口編程”。

  所以我們要做三個接口(正如你所猜測,一個model接口,一個view接口,一個control接口)。

  經過很多調查研究,和與acme人的費力咨詢,我們得到了很多有關詳細設計的信息。我們想確定我們可以設置的最大速度在前進,后退和轉彎中。我們也需要能夠加速,減速,左轉和右轉。我們的儀表盤必須顯示當前的速度和方向。

  實現所有這些需求是非常苛刻的,但是我們確信我們能夠做到...

  首先,我們考慮一下基本的項目。我們需要一些東西來表示方向和轉動請求。我們做了兩個枚舉類型:absolutedirection 和 relativedirection。

public enum absolutedirection
{
 north=0, east, south, west
}
public enum relativedirection
{
 right, left, back
}


  下面來解決control接口。我們知道control需要將請求傳遞給model,這些請求包括:accelerate, decelerate, 和 turn。我們建立一個ivehiclecontrol接口,并加入適當的方法。

public interface ivehiclecontrol
{
 void accelerate(int paramamount);
 void decelerate(int paramamount);
 void turn(relativedirection paramdirection);
}


  現在我們來整理model接口。我們需要知道汽車的名字,速度,最大速度,最大倒退速度,最大轉彎速度和方向。我們也需要加速,減速,轉彎的函數。

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 turn(relativedirection paramdirection);
 void accelerate(int paramamount);
 void decelerate(int paramamount);
}


  最后,我們來整理view接口。我們知道view需要暴露出control的一些機能,比如允許或禁止加速,減速和轉彎申請。

public interface ivehicleview
{
 void disableacceleration();
 void enableacceleration();
 void disabledeceleration();
 void enabledeceleration();
 void disableturning();
 void enableturning();
 }


  現在我們需要做一些微調使我們的這些接口能夠互相作用。首先,任何一個control都需要知道它的view和model,所以在我們的ivehiclecontrol接口中加入兩個函數:"setmodel" 和"setview":

public interface ivehiclecontrol
{
 void requestaccelerate(int paramamount);
 void requestdecelerate(int paramamount);
 void requestturn(relativedirection paramdirection);
 void setmodel(ivehiclemodel paramauto);
 void setview(ivehicleview paramview);
}


  下一個部分比較巧妙。我們希望view知道model中的變化。為了達到這個目的,我們使用觀察者模式。

  為了實施觀察者模式,我們需要將下面的函數加入到model(被view觀察):addobserver, removeobserver, 和 notifyobservers。

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 turn(relativedirection paramdirection);
 void accelerate(int paramamount);
 void decelerate(int paramamount);
 void addobserver(ivehicleview paramview);
 void removeobserver(ivehicleview paramview);
 void notifyobservers();
}


  ...并且將下面的函數加入到view(被model觀察)中。這樣做的目的是model會有一個view的引用。當model發生變化時,將會調用notifyobservers()方法,傳入一個對其自身的引用并調用update()通知view這個變化。

public class ivehicleview
{
 void disableacceleration();
 void enableacceleration();
 void disabledeceleration();
 void enabledeceleration();
 void disableturning();
 void enableturning();
 void update(ivehiclemodel parammodel);
}


  這樣我們就將我們的接口聯系起來了。在下面的代碼中我們只需要引用我們這些接口,這樣就保證了我們代碼的低耦合。任何顯示汽車狀態的用戶界面都需要實現ivehicleview,我們所有的acme都需要實現ivehiclemodel,并且我們需要為我們的acme汽車制作controls,這些control將實現ivehiclecontrol接口。

  下一步...在common中都需要什么

  我們知道所有的汽車都做相同的動作,所以我們接下來做一個基于“骨架”的共有的代碼來處理這些操作。這是一個抽象類,因為我們不希望任何人在“骨架”上開車(抽象類是不能被實例化的)。我們稱其為automobile。我們將用一個arraylist (from system.collections)來保持跟蹤所有感興趣的views(記住觀察者模式了嗎?)。我們也可以用老式的數組來記錄對ivehicleview的引用,但是現在我們已經很累了想快點結束這篇文章。如果你感興趣,看一下在觀察者模式中addobserver, removeobserver, 和notifyobservers,這些函數是怎樣和ivehicleview互相作用的。任何時間當有速度或方向變化時,automobile通知所有的ivehicleviews。

public abstract class automobile: ivehiclemodel
{
 "declarations "#region "declarations "
 private arraylist alist = new arraylist();
 private int mintspeed = 0;
 private int mintmaxspeed = 0;
 private int mintmaxturnspeed = 0;
 private int mintmaxreversespeed = 0;
 private absolutedirection mdirection = absolutedirection.north;
 private string mstrname = "";
 #endregion
 "constructor"#region "constructor"
 public automobile(int parammaxspeed, int parammaxturnspeed, int parammaxreversespeed, string paramname)
 {
  this.mintmaxspeed = parammaxspeed;
  this.mintmaxturnspeed = parammaxturnspeed;
  this.mintmaxreversespeed = parammaxreversespeed;
  this.mstrname = paramname;
 }
 #endregion
 "ivehiclemodel members"#region "ivehiclemodel members"
 public void addobserver(ivehicleview paramview)
 {
  alist.add(paramview);
 }
 public void removeobserver(ivehicleview paramview)
 {
  alist.remove(paramview);
 }
 public void notifyobservers()
 {
  foreach(ivehicleview view in alist)
  {
   view.update(this);
  }
 }
 public string name
 {
  get
  {
   return this.mstrname;
  }
  set
  {
   this.mstrname = value;
  }
 }
 public int speed
 {
  get
  {
   return this.mintspeed;
  }
 }
 public int maxspeed
 {
  get
  {
   return this.mintmaxspeed;
  }
 }
 public int maxturnspeed
 {
  get
  {
   return this.mintmaxturnspeed;
  }
 }
 public int maxreversespeed
 {
  get
  {
   return this.mintmaxreversespeed;
  }
 }
 public absolutedirection direction
 {
  get
  {
   return this.mdirection;
  }
 }
 public void turn(relativedirection paramdirection)
 {
  absolutedirection newdirection;
  switch(paramdirection)
  {
   case relativedirection.right:
    newdirection = (absolutedirection)((int)(this.mdirection + 1) %4);
    break;
   case relativedirection.left:
    newdirection = (absolutedirection)((int)(this.mdirection + 3) %4);
    break;
   case relativedirection.back:
    newdirection = (absolutedirection)((int)(this.mdirection + 2) %4);
    break;
   default:
    newdirection = absolutedirection.north;
    break;
  }
  this.mdirection = newdirection;
  this.notifyobservers();
 }
 public void accelerate(int paramamount)
 {
  this.mintspeed += paramamount;
  if(mintspeed >= this.mintmaxspeed) mintspeed = mintmaxspeed;
  this.notifyobservers();
 }
 public void decelerate(int paramamount)
 {
  this.mintspeed -= paramamount;
  if(mintspeed <= this.mintmaxreversespeed) mintspeed = mintmaxreversespeed;
  this.notifyobservers();
 }
 #endregion
}


  現在我們的"acme framework"已經做好了,我們只需要設立有形的類和接口。首先讓我們看看最后兩個類:control 和 model...

  這里我們有形的automobilecontrol實現ivehiclecontrol接口。我們的automobilecontrol也將設置view來依賴model 的狀態(當有向model的申請時檢測setview方法)。

  注意,我們只是有對ivehiclemodel的引用(而不是抽象類automobile )和對ivehicleview的引用(而不是具體的view),這樣保證對象間的低耦合。

public class automobilecontrol: ivehiclecontrol
{
 private ivehiclemodel model;
 private ivehicleview view;
 public automobilecontrol(ivehiclemodel parammodel, ivehicleview paramview)
 {
  this.model = parammodel;
  this.view = paramview;
 }
 public automobilecontrol()
 {}
 ivehiclecontrol members#region ivehiclecontrol members
 public void setmodel(ivehiclemodel parammodel)
 {
  this.model = parammodel;
 }
 public void setview(ivehicleview paramview)
 {
  this.view = paramview;
 }
 public void requestaccelerate(int paramamount)
 {
  if(model != null)
  {
   model.accelerate(paramamount);
   if(view != null) setview();
  }
 }
 public void requestdecelerate(int paramamount)
 {
  if(model != null)
  {
   model.decelerate(paramamount);
   if(view != null) setview();
  }
 }
 public void requestturn(relativedirection paramdirection)
 {
  if(model != null)
  {
   model.turn(paramdirection);
   if(view != null) setview();
  }
 }
 #endregion
 public void setview()
 {
  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();
  }
 }
}


  這里是我們的acme200sportscar類(從抽象類automobile繼承,實現了ivehiclemodel接口):

public class acme2000sportscar:automobile
{
 public acme2000sportscar(string paramname):base(250, 40, -20, paramname){}
 public acme2000sportscar(string paramname, int parammaxspeed, int parammaxturnspeed, int parammaxreversespeed):
 base(parammaxspeed, parammaxturnspeed, parammaxreversespeed, paramname){}
}


  現在輪到我們的view了...

  現在終于開始建立我們mvc最后一個部分了...view!

  我們要建立一個autoview來實現ivehicleview接口。這個autoview將會有對control和model接口的引用。

public class autoview : system.windows.forms.usercontrol, ivehicleview
{
 private ivehiclecontrol control = new acme.automobilecontrol();
 private ivehiclemodel model = new acme.acme2000sportscar("speedy");
}


  我們也需要將所有的東西包裝在usercontrol的構造函數中。

public autoview()
{
 // this call is required by the windows.forms form designer.
 initializecomponent();
 wireup(control, model);
}
public void wireup(ivehiclecontrol paramcontrol, ivehiclemodel parammodel)
{
 // if we're switching models, don't keep watching
 // the old one!
 if(model != null)
 {
  model.removeobserver(this);
 }
 model = parammodel;
 control = paramcontrol;
 control.setmodel(model);
 control.setview(this);
 model.addobserver(this);
}


  下面,加入我們的button和一個label來顯示acme2000 sports car的狀態還有狀態條用來為所有的buttons來顯示編碼。

private void btnaccelerate_click(object sender, system.eventargs e)
{
 control.requestaccelerate(int.parse(this.txtamount.text));
}
private void btndecelerate_click(object sender, system.eventargs e)
{
 control.requestdecelerate(int.parse(this.txtamount.text));
}
private void btnleft_click(object sender, system.eventargs e)
{
 control.requestturn(relativedirection.left);
}
private void btnright_click(object sender, system.eventargs e)
{
 control.requestturn(relativedirection.right);
}


  加入一個方法來更新接口...

public void updateinterface(ivehiclemodel auto)
{
 this.label1.text = auto.name + " heading " + auto.direction.tostring() + " at speed: " + auto.speed.tostring();
 this.pbar.value = (auto.speed>0)? auto.speed*100/auto.maxspeed : auto.speed*100/auto.maxreversespeed;
}


  最后我們實現ivehicleview接口的方法。

public void disableacceleration()
{
 this.btnaccelerate.enabled = false;
}
public void enableacceleration()
{
 this.btnaccelerate.enabled = true;
}
public void disabledeceleration()
{
 this.btndecelerate.enabled = false;
}
public void enabledeceleration()
{
 this.btndecelerate.enabled = true;
}
public void disableturning()
{
 this.btnright.enabled = this.btnleft.enabled = false;
}
public void enableturning()
{
 this.btnright.enabled = this.btnleft.enabled = true;
}
public void update(ivehiclemodel parammodel)
{
 this.updateinterface(parammodel);
}


  我們終于結束了!!!

  現在我們可以來測試acme2000 sports car了。一切按計劃進行,然后我們找到acme的主管人員,但他想要開一個載貨卡車而不是運動車。

  幸運的是我們用的是mvc!我們需要做的所有工作就是建立一個新的acmetruck類,包裝一下,完事!

public class acme2000truck: automobile
{
 public acme2000truck(string paramname):base(80, 25, -12, paramname){}
 public acme2000truck(string paramname, int parammaxspeed, int parammaxturnspeed, int parammaxreversespeed):
base(parammaxspeed, parammaxturnspeed, parammaxreversespeed, paramname){}
}


  在autoview中,我們只需要建立卡車包裝一下!

private void btnbuildnew_click(object sender, system.eventargs e)
{
 this.autoview1.wireup(new acme.automobilecontrol(), new acme.acme2000truck(this.txtname.text));
}


  如果我們想要一個新control只允許我們來每次加速或減速最大5mph,小意思!做一個slowpokecontrol(和我們的autocontrol相同,但是在申請加速度中做了限制)。

public void requestaccelerate(int paramamount)
{
 if(model != null)
 {
  int amount = paramamount;
  if(amount > 5) amount = 5;
  model.accelerate(amount);
  if(view != null) setview();
 }
}
public void requestdecelerate(int paramamount)
{
 if(model != null)
 {
  int amount = paramamount;
  if(amount > 5) amount = 5;
  model.accelerate(amount);
  model.decelerate(amount);
  if(view != null) setview();
 }
}


  如果我們想讓我們的acme2000 truck變得遲鈍,只需要在autoview中包裝。

private void btnbuildnew_click(object sender, system.eventargs e)
{
 this.autoview1.wireup(new acme.slowpokecontrol(), new acme.acme2000truck(this.txtname.text));
}


  最后,如果我們需要一個在web上的接口,我們要做的所有工作就是建立一個web項目在usercontrol中實現ivehicleview接口。

  結論

  正如你所看到的,使用mvc來構建代碼控制接口耦合性很低,很容易適應需求的改變。它也能使變化的影響減小,而且你可以在任何地方重用你的虛函數和接口。有很多時候我們可以在我們的項目中實現伸縮性,特別是在那些需求變化的時候,但是這需要下次再說了。

  于此同時,做下一個項目的時候記住mvc...你不會感到遺憾!
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 天台县| 惠州市| 长汀县| 丽江市| 古蔺县| 闵行区| 定西市| 涟源市| 龙江县| 稻城县| 准格尔旗| 湖州市| 浦北县| 恩施市| 华亭县| 宽城| 礼泉县| 内江市| 呼伦贝尔市| 竹北市| 蒙自县| 芜湖县| 临潭县| 乐山市| 澄迈县| 碌曲县| 库尔勒市| 胶南市| 合阳县| 民和| 额敏县| 和平区| 扎鲁特旗| 丹棱县| 双桥区| 内黄县| 错那县| 洞头县| 广东省| 垫江县| 牡丹江市|