依赖可以被认为是一个对象想要执行其功能,需要另外一个对象的相应功能。
假设A类的变化引起了B类的变化,则说明B类依赖于A类。
uml图(Diver依赖于Car):
public class Driver
{
public void drive(Car car)
{
car.move();
}
……
}
public class Car
{
public void move()
{
......
}
……
}
1、A类是B类中的(某中方法的)局部变量;
2、A类是B类方法当中的一个参数;
3、A类向B类发送消息,从而影响B类发生变化;
组合关系也是整体与部分的关系,但是整体与部分不可以分开。
组合关系中部分和整体具有统一的生存期。一旦整体对象不存在,部分对象也将不存在。即成员类的存在依赖于整体类
uml图:
public class Head
{
private Mouth mouth;
public Head()
{
mouth = new Mouth();
}
……
}
public class Mouth
{
……
}
Unity的框架是基于组合,没有入口控制
class 宇宙飞船
{
if (InputMana.getbutton(键盘空格))
{
Fire();
}
}
问题:当需求改变时,比如现在不用键盘空格,改为鼠标点击,为什么要在飞船类修改呢?
这是一个修改控制的问题,为什么要找飞船类解决。
class InputManger
{
if(键盘空格)
{
SendEvent(键盘空格被按下了);
}
}
class Meditor
{
监听事件;
收到不同消息采取不同措施(分发给需要听到该消息的人);
}
这样做的好处是依赖倒置,控制反转;在input类里面我们只关心记录发生了什么Input事件,不关心input事件触发了什么。
这样有点类似观察者模式,但是观察者模式也是直接注册,strangeioc框架在里面加入了一个中介层
是游戏的顶层,游戏入口,继承于Monobehaviour的,需要挂载在场景的GameObject中
class GameRoot : ContextView
{
context = new GameContext(this);
}
在里面bing绑定各个模块:view,meditor,command,event
public class GameContext : MVCSContext
{
public GameContext(MonoBehaviour view) : base(view)
{
}
public GameContext(MonoBehaviour view, ContextStartupFlags flags) : base(view, flags)
{
}
protected override void mapBindings()
{
//View/Mediator binding
//每当作为ExampleView时,这个绑定实例化一个新的ExampleMediator
//Fires its Awake method. The Mediator communicates to/from the View
//and to/from the App. This keeps dependencies between the view and the app
//separated. 中介和View通信,和app通信,使得视图和应用程序依赖
mediationBinder.Bind<InputView>().To<InputMeditor>();
//Event/Command binding
commandBinder.Bind(ExampleEvent.REQUEST_WEB_SERVICE).To<CallWebServiceCommand>();
//一旦映射完成,START事件就会被触发。
//请注意我们是如何将它绑定到“Once”的。这意味着一旦命令触发,映射就会消失。
commandBinder.Bind(ContextEvent.START).To<StartCommand>().Once();
}
}
负责监管表现层,如果发生变化,就用dispatcher.Dispatch(EVENT, Data);
继承于Monobehaviour的,需要挂载在场景的GameObject中。
应该由Meditor发送全局事件,View不能,View只能发送自己的事件给Meditor(语法上是可以直接发全局事件,为了统一好管理,最好是不发全局事件)
监听event事件(来自view或者全局),继承于Monobehaviour的,需要挂载在场景的GameObject中
Meditor可以直接dispacher,addListener,监听全局事件。没有必要发送到Service再Meditor→View,只有要发送到Service的需要用Command
多个View之间沟通示意图:
///
/// 注册后执行函数
///
public override void OnRegister()
{
//Listen to the view for an event
//view.dispatcher.AddListener(InputManager.CLICK_EVENT, onViewClicked);
view.dispatcher.AddListener(InputView.TRIGGER_LEFTJOYSTICK_EVENT, onTriggerLeftJoystick);
//Listen to the global event bus for events
//dispatcher.AddListener(InputManager.SCORE_CHANGE, onScoreChange);
view.init();
}
放置业务逻辑的地方;
默认情况下,在Execute()方法完成后立即清除命令。
对于异步命令(例如,呼叫服务并等待响应),在Execute()方法的顶部调用Retain(),这将防止过早清理。
但是请记住,一旦完成了命令,那么调用Release()是您的责任。
只有Command能够获得service和modle的单例,是可以直接注入model和service的;
[Inject]
public IExampleModel model{get;set;}
[Inject]
public IExampleService service{get;set;}
Command可以发送事件,这时meditor就会收到。Execute()是放置命令逻辑的地,在实例化的时候执行
public override void Execute()
{
Retain();
//Call the service. Listen for a response 告诉service监听这个事件,并且设置需要作出的回应
service.dispatcher.AddListener(ExampleEvent.FULFILL_SERVICE_REQUEST, onComplete);
service.Request("http://www.thirdmotion.com/ ::: " + counter.ToString());
}
相当于:
在绑定好的事件出现后,生成一个new Command(),记得Command完成后销毁:Release()
只跟command沟通,全局唯一(单例),放公用的方法