|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
捆绑编译器。用户不需要受制于厂家,自己就能将程序在新平台上编译运行。除了牛B轰轰的linux,估计也没有系统捆绑c/c++的编译器,而且许多新平台都无法支持复杂的c/c++编译器在上面直接运行。visual 在我们的开辟项目中利用MVC(Model-View-Control)形式的好处是,能够完整下降营业层和使用暗示层的互相影响。别的,我们会有完整自力的工具来操纵暗示层。MVC在我们项目中供应的这类工具和层之间的自力,将使我们的保护变得更复杂使我们的代码重用变得很简单(上面你将看到)。
作为一样平常的习气,我们晓得我们但愿坚持最低的工具间的依附,如许变更可以很简单的失掉满意,并且我们能够反复利用我们辛辛劳苦写的代码。为了到达这个目标我们将遵守一样平常的准绳“对接口编成,而不是对类”来利用MVC形式。
我们的任务,假如我们选择承受它...
我们被委任构建一个ACME2000SportsCar项目,我们的义务是做一个复杂的Windows画面来显现汽车的偏向和速率,使终端用户可以改动偏向,减速或是加速。固然将会有局限的扩大。
在ACME已有了传言,假如我们的项目乐成,我们终极还要为ACME2PickupTruck和ACME1Tricycle开辟一个类似的接口。作为开辟职员,我们也晓得ACME办理团队终极将问“如许是很棒的,我们可以在我们的intranet上看到它?”一切的这些出现在脑海中,我们想托付一个产物,使它可以简单的晋级以便可以包管未来我们可以有饭吃。
以是,同时我们决意“这是利用MVC的一个尽好情况”
我们的构架提要
如今我们晓得我们要利用MVC,我们必要指出它的实质。经由过程我们的实验得出MVC的三个部分:Model,Control和View。在我们的体系中,Model就是我们的汽车,View就是我们的画面,Control将这两个部分接洽起来。
为了改动Model(我们的ACME2000sportscar),我们必要利用Control。我们的Control将会发生给Model(我们的ACME2000sportscar)的哀求,和更新View,View就是我们的画面(UI)。
这看起来很复杂,可是这里发生了第一个要办理的成绩:当终端用户想做一个对ACME2000sportscar一个改动将会产生甚么,好比说减速或是转向?他们将经由过程View(ourwindowsform)用Control来提出一个变更的请求。
如今我们就剩下一个未办理成绩了。假如View没有需要的信息来显现Model的形态怎样办?我们必要再在我们的图中到场一个箭头:View将能请求Model的形态以便失掉它要显现的相干形态信息。
最初,我们的终极用户(司机)将会和我们的ACMEVehicleControl体系经由过程View来交互。假如他们想收回一个改动体系的请求,好比进步一点减速度,请求将会从View入手下手收回由Control处置。
Control将会向Model请求改动并将需要的变更反应在View上。好比,假如一个悍戾的司机对ACME2000SportsCar做了一个"floorit"请求,而如今行驶的太快不克不及转向,那末Control将会回绝这个请求并在View中关照,如许就避免了在交通拥堵是产生凄惨的连环相撞。
Model(theACME2000SportsCar)将关照View它的速率已进步,而View也将做得当的更新。
综上,这就是我们将构建的提要:
入手下手
作为老是想的远一点的开辟职员,我们想让我们的体系有一个久长而且优秀的性命周期。这就是说可以进大概的筹办好满意ACME的良多变更。为了做到这一点,我们晓得要遵守两条准绳...“包管你的类低耦合”,要到达这个方针,还要“对接口编程”。
以是我们要做三个接口(正如你所推测,一个Model接口,一个View接口,一个Control接口)。
经由良多查询拜访研讨,和与ACME人的吃力征询,我们失掉了良多有关具体计划的信息。我们想断定我们能够设置的最年夜速率在行进,前进和转弯中。我们也必要可以减速,加速,左转和右转。我们的仪表盘必需显现以后的速率和偏向。
完成一切这些需求长短常刻薄的,可是我们确信我们可以做到...
起首,我们思索一下基础的项目。我们必要一些器材来暗示偏向和动弹哀求。我们做了两个列举范例:AbsoluteDirection和RelativeDirection。
publicenumAbsoluteDirection
{
North=0,East,South,West
}
publicenumRelativeDirection
{
Right,Left,Back
}
上面来办理Control接口。我们晓得Control必要将哀求传送给Model,这些哀求包含:Accelerate,Decelerate,和Turn。我们创建一个IVehicleControl接口,并到场得当的办法。
publicinterfaceIVehicleControl
{
voidAccelerate(intparamAmount);
voidDecelerate(intparamAmount);
voidTurn(RelativeDirectionparamDirection);
}
如今我们来收拾Model接口。我们必要晓得汽车的名字,速率,最年夜速率,最年夜发展速率,最年夜转弯速率和偏向。我们也必要减速,加速,转弯的函数。
publicinterfaceIVehicleModel
{
stringName{get;set;}
intSpeed{get;set;}
intMaxSpeed{get;}
intMaxTurnSpeed{get;}
intMaxReverseSpeed{get;}
AbsoluteDirectionDirection{get;set;}
voidTurn(RelativeDirectionparamDirection);
voidAccelerate(intparamAmount);
voidDecelerate(intparamAmount);
}
最初,我们来收拾View接口。我们晓得View必要表露出Control的一些性能,好比同意或克制减速,加速和转弯请求。
publicinterfaceIVehicleView
{
voidDisableAcceleration();
voidEnableAcceleration();
voidDisableDeceleration();
voidEnableDeceleration();
voidDisableTurning();
voidEnableTurning();
}
如今我们必要做一些微调使我们的这些接口可以相互感化。起首,任何一个Control都必要晓得它的View和Model,以是在我们的IvehicleControl接口中到场两个函数:"SetModel"和"SetView":
publicinterfaceIVehicleControl
{
voidRequestAccelerate(intparamAmount);
voidRequestDecelerate(intparamAmount);
voidRequestTurn(RelativeDirectionparamDirection);
voidSetModel(IVehicleModelparamAuto);
voidSetView(IVehicleViewparamView);
}
下一个部分对照奇妙。我们但愿View晓得Model中的变更。为了到达这个目标,我们利用察看者形式。
为了实行察看者形式,我们必要将上面的函数到场到Model(被View察看):AddObserver,RemoveObserver,和NotifyObservers。
publicinterfaceIVehicleModel
{
stringName{get;set;}
intSpeed{get;set;}
intMaxSpeed{get;}
intMaxTurnSpeed{get;}
intMaxReverseSpeed{get;}
AbsoluteDirectionDirection{get;set;}
voidTurn(RelativeDirectionparamDirection);
voidAccelerate(intparamAmount);
voidDecelerate(intparamAmount);
voidAddObserver(IVehicleViewparamView);
voidRemoveObserver(IVehicleViewparamView);
voidNotifyObservers();
}
...而且将上面的函数到场到View(被Model察看)中。如许做的目标是Model会有一个View的援用。当Model产生变更时,将会挪用NotifyObservers()办法,传进一个对其本身的援用并挪用Update()关照View这个变更。
publicclassIVehicleView
{
voidDisableAcceleration();
voidEnableAcceleration();
voidDisableDeceleration();
voidEnableDeceleration();
voidDisableTurning();
voidEnableTurning();
voidUpdate(IVehicleModelparamModel);
}
如许我们就将我们的接口接洽起来了。鄙人面的代码中我们只必要援用我们这些接口,如许就包管了我们代码的低耦合。任何显现汽车形态的用户界面都必要完成IVehicleView,我们一切的ACME都必要完成IVehicleModel,而且我们必要为我们的ACME汽车制造Controls,这些Control将完成IVehicleControl接口。
下一步...在common中都必要甚么
我们晓得一切的汽车都做不异的举措,以是我们接上去做一个基于“骨架”的共有的代码来处置这些操纵。这是一个笼统类,由于我们不但愿任何人在“骨架”上开车(笼统类是不克不及被实例化的)。我们称其为Automobile。我们将用一个ArrayList(fromSystem.Collections)来坚持跟踪一切感乐趣的Views(记着察看者形式了吗?)。我们也能够用老式的数组来纪录对IVehicleView的援用,可是如今我们已很累了想快点停止这篇文章。假如你感乐趣,看一下在察看者形式中AddObserver,RemoveObserver,和NotifyObservers,这些函数是如何和IVehicleView相互感化的。任什么时候间当有速率或偏向变更时,Automobile关照一切的IVehicleViews。
publicabstractclassAutomobile:IVehicleModel
{
"Declarations"#region"Declarations"
privateArrayListaList=newArrayList();
privateintmintSpeed=0;
privateintmintMaxSpeed=0;
privateintmintMaxTurnSpeed=0;
privateintmintMaxReverseSpeed=0;
privateAbsoluteDirectionmDirection=AbsoluteDirection.North;
privatestringmstrName="";
#endregion
"Constructor"#region"Constructor"
publicAutomobile(intparamMaxSpeed,intparamMaxTurnSpeed,intparamMaxReverseSpeed,stringparamName)
{
this.mintMaxSpeed=paramMaxSpeed;
this.mintMaxTurnSpeed=paramMaxTurnSpeed;
this.mintMaxReverseSpeed=paramMaxReverseSpeed;
this.mstrName=paramName;
}
#endregion
"IVehicleModelMembers"#region"IVehicleModelMembers"
publicvoidAddObserver(IVehicleViewparamView)
{
aList.Add(paramView);
}
publicvoidRemoveObserver(IVehicleViewparamView)
{
aList.Remove(paramView);
}
publicvoidNotifyObservers()
{
foreach(IVehicleViewviewinaList)
{
view.Update(this);
}
}
publicstringName
{
get
{
returnthis.mstrName;
}
set
{
this.mstrName=value;
}
}
publicintSpeed
{
get
{
returnthis.mintSpeed;
}
}
publicintMaxSpeed
{
get
{
returnthis.mintMaxSpeed;
}
}
publicintMaxTurnSpeed
{
get
{
returnthis.mintMaxTurnSpeed;
}
}
publicintMaxReverseSpeed
{
get
{
returnthis.mintMaxReverseSpeed;
}
}
publicAbsoluteDirectionDirection
{
get
{
returnthis.mDirection;
}
}
publicvoidTurn(RelativeDirectionparamDirection)
{
AbsoluteDirectionnewDirection;
switch(paramDirection)
{
caseRelativeDirection.Right:
newDirection=(AbsoluteDirection)((int)(this.mDirection+1)%4);
break;
caseRelativeDirection.Left:
newDirection=(AbsoluteDirection)((int)(this.mDirection+3)%4);
break;
caseRelativeDirection.Back:
newDirection=(AbsoluteDirection)((int)(this.mDirection+2)%4);
break;
default:
newDirection=AbsoluteDirection.North;
break;
}
this.mDirection=newDirection;
this.NotifyObservers();
}
publicvoidAccelerate(intparamAmount)
{
this.mintSpeed+=paramAmount;
if(mintSpeed>=this.mintMaxSpeed)mintSpeed=mintMaxSpeed;
this.NotifyObservers();
}
publicvoidDecelerate(intparamAmount)
{
this.mintSpeed-=paramAmount;
if(mintSpeed<=this.mintMaxReverseSpeed)mintSpeed=mintMaxReverseSpeed;
this.NotifyObservers();
}
#endregion
}
如今我们的"ACMEFramework"已做好了,我们只必要设立无形的类和接口。起首让我们看看最初两个类:Control和Model...
这里我们无形的AutomobileControl完成IVehicleControl接口。我们的AutomobileControl也将设置View来依附Model的形态(当有向Model的请求时检测SetView办法)。
注重,我们只是有对IVehicleModel的援用(而不是笼统类Automobile)和对IVehicleView的援用(而不是详细的View),如许包管工具间的低耦合。
publicclassAutomobileControl:IVehicleControl
{
privateIVehicleModelModel;
privateIVehicleViewView;
publicAutomobileControl(IVehicleModelparamModel,IVehicleViewparamView)
{
this.Model=paramModel;
this.View=paramView;
}
publicAutomobileControl()
{}
IVehicleControlMembers#regionIVehicleControlMembers
publicvoidSetModel(IVehicleModelparamModel)
{
this.Model=paramModel;
}
publicvoidSetView(IVehicleViewparamView)
{
this.View=paramView;
}
publicvoidRequestAccelerate(intparamAmount)
{
if(Model!=null)
{
Model.Accelerate(paramAmount);
if(View!=null)SetView();
}
}
publicvoidRequestDecelerate(intparamAmount)
{
if(Model!=null)
{
Model.Decelerate(paramAmount);
if(View!=null)SetView();
}
}
publicvoidRequestTurn(RelativeDirectionparamDirection)
{
if(Model!=null)
{
Model.Turn(paramDirection);
if(View!=null)SetView();
}
}
#endregion
publicvoidSetView()
{
if(Model.Speed>=Model.MaxSpeed)
{
View.DisableAcceleration();
View.EnableDeceleration();
}
elseif(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接口):
publicclassACME2000SportsCar:Automobile
{
publicACME2000SportsCar(stringparamName):base(250,40,-20,paramName){}
publicACME2000SportsCar(stringparamName,intparamMaxSpeed,intparamMaxTurnSpeed,intparamMaxReverseSpeed):
base(paramMaxSpeed,paramMaxTurnSpeed,paramMaxReverseSpeed,paramName){}
}
如今轮到我们的View了...
如今终究入手下手创建我们MVC最初一个部分了...View!
我们要创建一个AutoView来完成IVehicleView接口。这个AutoView将会有对Control和Model接口的援用。
publicclassAutoView:System.Windows.Forms.UserControl,IVehicleView
{
privateIVehicleControlControl=newACME.AutomobileControl();
privateIVehicleModelModel=newACME.ACME2000SportsCar("Speedy");
}
我们也必要将一切的器材包装在UserControl的机关函数中。
publicAutoView()
{
//ThiscallisrequiredbytheWindows.FormsFormDesigner.
InitializeComponent();
WireUp(Control,Model);
}
publicvoidWireUp(IVehicleControlparamControl,IVehicleModelparamModel)
{
//IfwereswitchingModels,dontkeepwatching
//theoldone!
if(Model!=null)
{
Model.RemoveObserver(this);
}
Model=paramModel;
Control=paramControl;
Control.SetModel(Model);
Control.SetView(this);
Model.AddObserver(this);
}
上面,到场我们的Button和一个label来显现ACME2000SportsCar的形态另有形态条用来为一切的Buttons来显现编码。
privatevoidbtnAccelerate_Click(objectsender,System.EventArgse)
{
Control.RequestAccelerate(int.Parse(this.txtAmount.Text));
}
privatevoidbtnDecelerate_Click(objectsender,System.EventArgse)
{
Control.RequestDecelerate(int.Parse(this.txtAmount.Text));
}
privatevoidbtnLeft_Click(objectsender,System.EventArgse)
{
Control.RequestTurn(RelativeDirection.Left);
}
privatevoidbtnRight_Click(objectsender,System.EventArgse)
{
Control.RequestTurn(RelativeDirection.Right);
}
到场一个办法来更新接口...
publicvoidUpdateInterface(IVehicleModelauto)
{
this.label1.Text=auto.Name+"heading"+auto.Direction.ToString()+"atspeed:"+auto.Speed.ToString();
this.pBar.Value=(auto.Speed>0)?auto.Speed*100/auto.MaxSpeed:auto.Speed*100/auto.MaxReverseSpeed;
}
最初我们完成IVehicleView接口的办法。
publicvoidDisableAcceleration()
{
this.btnAccelerate.Enabled=false;
}
publicvoidEnableAcceleration()
{
this.btnAccelerate.Enabled=true;
}
publicvoidDisableDeceleration()
{
this.btnDecelerate.Enabled=false;
}
publicvoidEnableDeceleration()
{
this.btnDecelerate.Enabled=true;
}
publicvoidDisableTurning()
{
this.btnRight.Enabled=this.btnLeft.Enabled=false;
}
publicvoidEnableTurning()
{
this.btnRight.Enabled=this.btnLeft.Enabled=true;
}
publicvoidUpdate(IVehicleModelparamModel)
{
this.UpdateInterface(paramModel);
}
我们终究停止了!!!
如今我们能够来测试ACME2000SportsCar了。统统按企图举行,然后我们找到ACME的主管职员,但他想要开一个载货卡车而不是活动车。
侥幸的是我们用的是MVC!我们必要做的一切事情就是创建一个新的ACMETruck类,包装一下,完事!
publicclassACME2000Truck:Automobile
{
publicACME2000Truck(stringparamName):base(80,25,-12,paramName){}
publicACME2000Truck(stringparamName,intparamMaxSpeed,intparamMaxTurnSpeed,intparamMaxReverseSpeed):
base(paramMaxSpeed,paramMaxTurnSpeed,paramMaxReverseSpeed,paramName){}
}
在AutoView中,我们只必要创建卡车包装一下!
privatevoidbtnBuildNew_Click(objectsender,System.EventArgse)
{
this.autoView1.WireUp(newACME.AutomobileControl(),newACME.ACME2000Truck(this.txtName.Text));
}
假如我们想要一个新Control只同意我们来每次减速或加速最年夜5mph,小意义!做一个SlowPokeControl(和我们的AutoControl不异,可是在请求减速度中做了限定)。
publicvoidRequestAccelerate(intparamAmount)
{
if(Model!=null)
{
intamount=paramAmount;
if(amount>5)amount=5;
Model.Accelerate(amount);
if(View!=null)SetView();
}
}
publicvoidRequestDecelerate(intparamAmount)
{
if(Model!=null)
{
intamount=paramAmount;
if(amount>5)amount=5;
Model.Accelerate(amount);
Model.Decelerate(amount);
if(View!=null)SetView();
}
}
假如我们想让我们的ACME2000Truck变得愚钝,只必要在AutoView中包装。
privatevoidbtnBuildNew_Click(objectsender,System.EventArgse)
{
this.autoView1.WireUp(newACME.SlowPokeControl(),newACME.ACME2000Truck(this.txtName.Text));
}
最初,假如我们必要一个在web上的接口,我们要做的一切事情就是创建一个Web项目在UserControl中完成IVehicleView接口。
结论
正如你所看到的,利用MVC来构建代码把持接口耦合性很低,很简单顺应需求的改动。它也能使变更的影响减小,并且你能够在任何中央重用你的虚函数和接口。有良多时分我们能够在我们的项目中完成伸缩性,出格是在那些需求变更的时分,可是这必要下次再说了。
于此同时,做下一个项目标时分记着MVC...你不会感应遗憾!也不知道,我同学昨天说数据挖掘很好。 |
|