Unity StrangeIoC框架_strige ioc-程序员宅基地

技术标签: strangeIoc  Unity  

Unity StrangeIoC(一)



正式之前先说说基础的概念:
首先是MVC框架,MVC框架的思路是将业务逻辑、数据、界面显示分离,网上很多关于MVC的资料,这里不再过多的描述了。
下面截图来自wikipedia的mvc框架:
然后是控制反转(包括依赖注入和依赖查找),控制反转也是著名框架spring框架的核心。
对于控制反转(Inversion of Control,缩写IOC)的依赖注入,先用一个C#示例代码演示一下。比如设计一个玩家攻击敌人的游戏,玩家可以装备手枪,步枪。最简单的代码设计实现如下:

public   class   Player
{
     public   string   gunName =  "ShouQiang" ;
     public   void   Attack(Enemy enemy)
     {
         if (gunName ==  "ShouQiang" )
             enemy.hp -= 10;
         else   if (gunName =  '' BuQiang")
         ememy.hp -= 20;
     }
}

如上述代码,假如项目中多了一个(机枪),需要重写player类,重写攻击逻辑(if..else)设计不合理。重新设计,代码可以用下面的方实现:

public   interface   IGun {
     voidAttack(Enemy eneny);
}
public   class   ShouQiang : IGun
{
     public   void   Attack(Enemy eneny)
     {
         enemy.hp -=10;
     }
}
public   class   BuQiang : IGun
{
     public   void   Attack(Enemy enemy)
     {
         enemy.hp -= 20;
     }
}
public   class   Player
{
     public   IGun gun = newShouQiang(); 
     public   void   Attack(Enemy enemy)
     {
         gun. Attack(enemy);
     }
}
public   class   Eneny
{
     public   int   hp;
}

如果再增加机枪,直接增加一个机枪类继承IGun接口就可以了 playe类中
public IGun gun = new ShouQiang();简单实现了一个注入.

下面正式介绍strangeioc.
正如strangeioc描述的一样,总体上说它是根据控制反转和解耦和原理设计的,支持依赖注入. 继续引入一个示例,如果写一个单玩家游戏,死亡后将最高分数提交到facebook ,代码如下:

public   class   MyShip: MonoBehaviour {
     private   FacebookService facebook;
     private   int   myScore,
     void   Awake()
     {
         facebook = FacebookService.getlnstance(),
     }
     void   onDie()
     {
         if   (score > highScore) 
             facebook.PostScore(myScore),
     }
}

这样做有两个问题:
1.ship作为控制角色,但是除了要通知facebook上传分数还要处理代码逻辑.将自身与游戏逻辑与 facebook逻辑关联(髙耦合)
2.FacebookService是单键,如果我们改为要提交到Twitter..or Google+... 怎么办?或者FacebookService里面的方法有变更怎么办?
如果代码如上,需要重构很多代码才能完成相应的功能,但是通过引入ioc,重构将会方便很多。

public   class   MyShip : MonoBehavior
{
     void   OnDie()
     {
         dispatcher.Dispatch(GameEvent.SHIP_DEAD);
     }
}

视图模块出发了死亡逻辑,它(View)需要知道的仅仅是这些就够了,然后将死亡消息发送出去。
某个模块的代码用来接收死亡消息,然后做出处理,如下:

public   class   OnShipDeathCommand: EventCommand
{
     [Inject]
     ISocialService socialService { get set ,}

     [Inject]
     IScoreModel scoreModel { get   set ,}

     public   override   void   Execute()
     {
         if   (scoreModel.score > scoreModel.highScore) 
             socialService.PostScore(scoreModel.score);
     }
}

[Inject]标签实现接口,而不是实例化类 

#if UNITY_ANDROID
injectionBinder.Bind<ISocialService>().To<GoogleService>().AsSingleton();
#else
injectionBinder.Bind<ISocialService>().To<FacebookService>().AsSingleton(); 
#endif
//...or...
//injectionBinder.Bind<ISocialService>().To<MultiServiceResolver>().AsSingleton();
 
injectionBinder.Bind<IScoreModel>() To<ScoreMcxiel>() AsSIngleton();
commandBinder.Bind(GameEvent.SHIP_DEAD , OnShipDeathCommand);

用IOC(控制反转)我们不用关注具体逻辑,也不同自己再创建单键。
ship触发Command来执行逻辑,每个模块之间都是独立的。
1> commandBinder.Bind(GameEvent.SHIP_DEAD , OnShipDeathCommand);
将事件和对应逻辑绑定在了一起。

2> dispatcher.Dispatch(GameEvent.SHIP_DEAD)
就是发出事件,但是具体做什么事情不需要了解。




Unity StrangeIoC(二)



strangeioc第一大部分:1.Binding(绑定)

strange的核心是绑定,我们可以将一个或者多个对象与另外一个或者多个对象绑定(连接)在一起。将接口与类绑定来实现接口,将事件与事件接受绑定在一起。或者绑定两个类,一个类被创建的时候另一个自动创建。如果你再Unity里面用过SendMessage方法,或者一个类引用另一个类,再或者式if...else语句,从某种形式上来说也是一种绑定。

但是直接绑定是有问题的,导致代码不易修改(不再是高聚合低耦合).比如一个spaceship类,里面包含gun发射和键盘控制功能,当需求变更为使用鼠标控制时,你就需要重新修改spaceship方法,但是仅仅是控制功能的需求改变了,为什么要重写spaceship方法呢?
如果你自定义一个鼠标控制类(mousecontrol)。然后spaceship里面调用鼠标控制类,你还是采用的直接绑定的方法。当需求变为键盘控制的时候,你又要去重新修改spaceship去调用键盘控制的class。

strange可以实现间接绑定从而使你的代码减轻对其他模块的依赖(低耦合)。这是面向对象编程(Object-Oriented Programming)的根基和宗旨。通过strangeioc绑定你的代码会变得更加灵活。

The structure of a binding

strange的binding由两个必要部分和一个可选部分组成,必要部分是a key and a value, key触发value,因此一个事件可以触发回调,一个类的实例化可以触发另一个类的实例化。可选部分是name,它可以区分使用相同key的两个binding。下面的三种绑定方法其实都是一样的,语法不同而已:

1.Bind<IDrive>().To<WarpDrive>();

2.Bind(typeof(IDrive)).To(typeof(WarpDrive));

3.IBinding binding = Bind<IDrive>();
bingding.To<WarpDrive>();


bind是key,to是value。
当使用非必要部分Name时,如下:

Bind<IComputer>().To<SuperComputer>().ToName("DeepThought");


MVCSContext式推荐的版本,它包含下面介绍的所有拓展,是使用strange最简单的途径


strangeioc第二大部分:2.Extensions

看strange的介绍,它是一个依赖注入框架,虽然它具有依赖注入的功能,但是核心思想还是绑定。

接下来讲介个关于binder(绑定)的扩展。


The injection extension(注入)

在binder扩展中最接近Inversion-of-Control(IoC)控制反转思想的是注入。
大家应该很熟悉接口的使用方法,接口本身没有是实现方法,只是定义类中的规则:

interface   ISpaceship
{
     void   input( float   angle, float   velocity);
     IWeapon weapon{  get set ; }
}

使用另一个类来实现这个接口:

class   Spaceship : ISpaceship
{
     public   void   input( float   angle, float   velocity)
     {
         //do stuff here
     }
     IWeapon weapon{  get set ; }
}


如果采用上面的写法,Spaceship类里面不用再写检测输入(input)的功能了,只需要处理输入就可以了,不再需要武器逻辑,仅仅式注入武器实例就可以了。到现在已经迈出一大步了。但是出现了一个问题,谁告诉spaceship,我们使用何种武器?我们可以采用工厂模式给weapon赋值具体的武器实例,简单的工厂模式如下:

public   interface   IWeapon
{    
     void   Attack();
}
public   class   BuQiang : IWeapon
{
     public   void   Attack(){ //敌人掉血逻辑
 
     }
}
public   class   ShouQiang : IWeapon
{
     public   void   Attack() { //敌人掉血逻辑
 
     }
}

上面创建好了武器的约定接口和两种武器,下面创建武器工厂:

public   class   MeaponFactory 
{
     public   IWeapon GetWeapon( string   name)
     {
         if (name ==  "BuQiang"
             return   new   BuQiang(); 
         else   if   (name ==  "ShouQiang"
             return   new   ShouQiang(); 
         return   null ;
     }
}

取武器直接使用

IWeapon weapon =  new   WeaponFactory().GetWeapon( "BuQiang" );

(ps. 也有人说,取武器直接IWeapon weapon = new BuQiang();使用工厂反而麻烦,但是如果我们可以从美国军械库去到步枪,手枪。中国军械库也可以去到步枪,手枪。使用工厂模式就方便了许多:

IWeapon weapon =  new   AmericaWeaponFactory().GetWeapon( "BuQiang" );
IWeapon weapon =  new   ChinaWeaponFactory().GetWeapon( "BuQiang" );

但是这样做并没有解决根本问题,factorymanager需要包括/返回各种武器的实例。现在我们引入一个全新的模式:Dependency Injection(DI)依赖注入:

DI模式中一个类对另一个类的引用,通过发射的方式实现(比如我们的ISpaceship中的weapon不再直接复制类的实例/或者通过工厂赋值类的实例(这样它们之间仍旧存在引用关系))而是通过反射(Reflection)的方式实现。

首先我将IWeapon和具体的手枪实例绑定:

injectionBinder.Bind<IWeapon>().To<ShouQiang>();

然后ISpaceship中weapon赋值如下:

[Inject]
public IWeapon weapon { get; set; }


当然如果有多个实现方式可以使用如下方式:

injectionBinder.Bind<IWeapon>().To<ShouQiang>().ToName( "ShouQiang" );
injectionBinder.Bind<IWeapon>().To<BuQiang>().ToName( "BuQiang" );

然后ISpaceship中weapon赋值如下:

[Inject( "BuQiang" )]
public   IWeapon weapon {  get set ; }
 
或者:

[Inject( "ShouQiang" )]
public   IWeapon weapon {  get set ; }




Unity StrangeIoC(三)


第二个扩展部分:

The reflector extension(反射)

List<Type> list =  new   List<Type>();
 
list.Add(tpyeof(Borg));
list.Add( typeof (DeathStar));
list.Add( typeof (Galactus));
list.Add( typeof (Berserker));
 
//count should equal 4, verifying that all four classes were reflected
int   count = injectionBinder.Reflect(list);

看官网介绍,可以批量反射,全部反射等待.. injectionBinder.ReflectAll();

下面接着说扩展部分中的第三个扩展(调度器)

The dispatcher extension

从原理上来说dispatcher相当于观察者模式中的公告板,允许客户监听他,并且告知当前发生的事件。但在strangeioc中,通过EventDispatcher方式实现,EventDispatcher绑定触发器来触发带参数/不带参数的方法。
触发器通常是string或者是枚举类型(触发器你可以理解为key,或者事件的名称,名称对应着触发的方法).
如果事件有返回值,他将存在IEvent,编辑逻辑实现这个接口就能得到返回值,标注的strangeioc事件叫做TmEvent.如果你在用MVCSContext,有个全局的EventDispatcher叫:contextDispatcher会自动注入,你可以用它来传递事件。

There's also acrossContextDispatcher for communicating between Contexts。
同样有一个accossContextDispatcher可以在contexts传递事件。
使用EventDispatcher需要做两个事情就可以,调度/设置事件和监听事件。

dispatcher.AddListener("FIRE_MISSILE",onMissleFire);

然后事件就会处于监听状态,直到FIRE_MISSLE事件被触发,然后执行相应的onMissleFire方法。

当然Key也可以不适用字符串而是枚举类型。

相关的几个Api:

dispatcher.AddListener("FIRE_MISSILE",onMissleFire);
dispatcher.RemoveListener("FIRE_MISSILE",onMissleFire);
dispatcher.UpdateListener("FIRE_MISSILE",onMissleFire);

派发消息:

dispatcher.Dispatch("FIRE_MISSLE")。




Unity StrangeIoC(四)




继续扩展部分的第四个扩展(命令)

The command extension

除了将事件绑定到方法以外,还可以将他们与命令绑定。命令式mvc框架的指挥者。
在strangeioc的MVCSContext中,CommandBinder监听所有来自dispatcher分发的事件.
Signals(上文提到的消息(signal)与事件(event))也可以绑定到command.

using   strange.extensions.command.impl; 
using   com.example.spacebattle.utils; 
namespace   com.example.spacebattle.controller
{
     class   StartGameCommand : EventCommand
     {
         [Inject]
         public   ITimer ganeTimer {  get set ; }
         overridepublic  void   Execute()
         {
             gameTimer.start();
             dispatcher.dispatch(GameEvent.STARTED);
         }
     }
}

如果是有网络请求,有返回,可以采用这样的方法实现:

using   strange.extensions.command.impl; 
using   com.example.spacebattle.service;
namespace   com.example.spacebattle.controller
{
     class   PostScoreCommand : EventCommand
     {
         [Inject]
         IServer gameServe {  get set   ;} 
         override   public   void   Execute()
         {
             Retain();
             int   score = ( int )evt.data;
             gameServer.dispatcher.AddListener(
                         ServerEvent.SUCCESS, onSuccess);               
             gameServer.dispatcher.AddListener(
                         ServerEvent.FAILURE, onFailure);    
             gaweServer.send(score);
         }
         private   void   onSuccess()
         {
             gameServer.dispatcher.RemoveListener(
                         ServerEvent.SUCCESS, onSuccess);     
             gameServer.dispatcher.RemoveListener(
                         ServerEvent.FAILURE, onFailure); 
             //…do something to report success…
             Release();
         }
         private   void   onFailure( object   payload)
         {
             gameServer.dispatcher.RemoveListener(
                         ServerEvent.SUCCESS, onSuccess);     
             gameServer.dispatcher.RemoveListener(
                         ServerEvent.FAIlURE, onFailure);
             //...do sowething to report failure...
             Release();
         }
     }
}


将命令和该类绑定起来

commandBinder.Bind(ServerEvent.POST_SCORE).To<PostScoreCommand>();

命令绑定多个事件:

commandBinder.Bind(GameEvent.HIT).To<DestroyEnemyCommand>()
.To<UpdateScoreCommand>();
解除绑定:

commandBinder.Unbind(GameEvent.POST_SCORE);

按顺序触发命令绑定事件:

commandBinder.Bind(GameEvent.HIT).InSequence()
.To<CheckLevelClearedCommand>()
.To<EndLevelCommand>()
.To<GameOverCommand>();






Unity StrangeIoC(五)



扩展部分的第五个扩展

The signal extension(消息)

消息是一种代替EventDispatcher的分发机制,与EventDispatcher相比,消息1.分发结果不再创建实例,因此也不需要回收更多的垃圾。2.更安全,当消息与回调不匹配时,就会断开执行。官网也推荐使用signal来兼容后续版本。

Signal< int > signalDispatchesInt =  new   Signal< int >(); 
Signal< string > signalDispatchesString =  new   Signal< string >();

//Add a callback with an int parameter
signalDispatchesInt AddListener(callbacklnt);
//Add a callback with a string parameter    
signalDispatchesString AddListener(callbackString); 
 
signalDispatchesInt.Oispatch(42);  //dispatch an int 
signalDispatchesString.Oispatch( "Ender Wiggin" );  //dispatch a string

void   callbacklnt( int   value)
{
//Do something with this int
}

void   callbackString( string   value)
{
//Do something with this string
}

消息最多可以使用四个参数:

//works
Signal signal0 =  new   Signal();
 
//works
Signal<SomeValueObject> signal1 =   new   Signal<SomeValueObject>();
 
//works
Signal< int , string > signal2 =   new   Signal< int , string >();
 
//works
Signal< int , int > signal3 =   new   Signal< int , int >();
 
//works
Signal<SomeValueObject, int , string ,MonoBehavior> signal4 =   new  
Signal<SomeValueObject, int , string ,MonoBehavior>();
 
//FAILS!!!!  Too many params.
Signal< int , string ,Vector2,Rect> signal5 =   new  
Signal< int , string ,Vector2,Rect>();

消息绑定:
commandBinder.Bind<SomeSignal>().To<SomeCommand>();

看下一个示例:
commandBinder.Bind<ShipDestroyedSignal>().To<ShipDestroyedCommand>();

然后:

[Inject]
public   ShipDestroyedSignal shipDestroyedSignal{  get set ; }
 
// imagining that the Mediator holds avalue for this ship
private   int   basePointValue;
 
//Something happened that resulted in destruction
private   void   OnShipDestroyed()
{
     shipDestroyedSignal.Dispatch(view,basePointValue);
}

再然后:

using   System;
using   strange.extensions.command.impl;
using   UnityEngine;
 
namespace   mynamespace
{
     //Note how we extend Command,not EventCommand
     public   class   ShipDestroyedCommand: Command
     {
         [inject]
         public   MonoBehavior view{  get set ; }
 
         [inject]
         public   int   basePointValue{  get set ; }
 
         public   override   void   Execute()
         {
             //Do unspeakable things to the destroyed ship
         }
     }
}

再给出一个strangeios的demo里面的代码:


using   System;
using   UnityEngine;
using   strange.extensions.context.api;
using   strange.extensions.context.impl;
using   strange.extensions.dispatcher.eventdispatcher.api;
using   strange.extensions.dispatcher.eventdispatcher.impl;
using   strange.extensions.command.api;
using   strange.extensions.command.impl;
 
namespace   strange.examples.signals
{
   public   class   SignalsContext : MVCSContext
   {
       public   SignalsContext (MonoBehaviour view) :  base (view)
       {
       }
       public   SignalsContext (MonoBehaviour view, 
ContextStartupFlags flags)
  :  base (view, flags)
       {
       }
    
       // Unbind the default EventCommandBinder and rebind the SignalCommandBinder
       protected   override   void   addCoreComponents()
       {
          base .addCoreComponents();
         injectionBinder.Unbind<ICommandBinder>();
         injectionBinder.Bind<ICommandBinder>()
.To<SignalCommandBinder>().ToSingleton();
       }
          
       // Override Start so that we can fire the StartSignal 
       override   public   IContext Start()
       {
          base .Start();
          StartSignal startSignal= (StartSignal)injectionBinder
.GetInstance<StartSignal>()
          startSignal.Dispatch();
          return   this ;
      }
          
       protected   override   void   mapBindings()
       {
          injectionBinder.Bind<IExampleModel>()
.To<ExampleModel>().ToSingleton();
          injectionBinder.Bind<IExampleService>()
.To<ExampleService>().ToSingleton();
          mediationBinder.Bind<ExampleView>().To<ExampleMediator>();
            
          commandBinder.Bind<CallWebServiceSignal>()
.To<CallWebServiceCommand>();
              
          //StartSignal is now fired instead of the START event.
          //Note how we've bound it "Once". This means that the mapping goes away as soon as the command fires.
          commandBinder.Bind<StartSignal>().To<StartCommand>().Once();
              
          //In MyFirstProject, there's are SCORE_CHANGE and FULFILL_SERVICE_REQUEST Events.
          //Here we change that to a Signal. The Signal isn't bound to any Command,
          //so we map it as an injection so a Command can fire it, and a Mediator can receive it
          injectionBinder.Bind<ScoreChangedSignal>().ToSingleton();
          injectionBinder.Bind<FulfillWebServiceRequestSignal>()
.ToSingleton();
         }
     }
}

signal 既可以通过command添加绑定监听也可以通过AddLister




Unity StrangeIoC(六)


继续扩展部分的下一个扩展

The mediation extension(调节器(中介模式))

mediationContext是唯一一个专为Unity设计的部分,因为mediation关系的式对view(GameObject)的操作,由于view部分天生的不确定性,我们推荐view由两种不同的monobehavior组成:View and Mediator.

view就是mvc中的v,一个view就是一个你可以编写逻辑,控制可见部分的monobehavior.
这个类可以附加(拖拽)到Unity编辑器来关联GameObject.但是不建议吧mvc的models和controller写在view中。

Mediator类的职责是知晓view和整个应用的运行。它也会获取整个app中分发和接受的时间和消息,但是因为mediator的设计,建议使用命令模式(command)来做这部分的功能。

mediator示例:

using   strange.extensions.mediation.ipml; 
using   com.example.spacebattle.events; 
using   com.example.spacebattle.model; 
namespace   com.example.spacebattle.view 
{
     class   DashboardMediator : EventMediator
     {
         [Inject]
         public   DashboardView view {  get set ; } 
         override   public   void   OnRegister()
         {
             view.init();
             dispatcher.Addlistener
                     (ServiceEvent.FULFILL_ONLINE_PLAYERS, onPlayers); 
             dispatchers Dispatch
                     (ServiceEvent.REQUEST_ONLINE_PLAYERS);
         }
         override   public   void   OnRemove()
         {
             dispatcher.RemoveListener
                     (ServiceEvent.FULFILl_ONLINE_PLAYERS, onPlayers);
         }
         private   void   onPlayers(IEvent evt)
         {
             IPlayers[] playerList = evt.data  as   IPlayers[];
             view.updatePlayeCount(playerlist. Length);
         }
     }
}

示例说明:

1.当完成注入之后,DashboardView变为当前的场景所挂载的view.
2.当完成注入之后(可以理解为结构体的方式) OnRegister()方法会立即执行。可以用这个方法来做初始化。
3.contextDispatcher可以扩展任何的EventMediator。
4.OnRemove()清理使用,当一个view在被销毁前调用,并且要移除你所添加的所有监听器。
5.示例中的view暴力ultimate两个接口,但是在程序设计的时候你可能会更多,但是有一条理念:中介者不处理GameObject相关属性更新。
可以这样来绑定:

mediationBinder.Binder<DashboardView>().To<DashboardMediator>();

注意:
1.并不是所有MonoBehavior都需要限定成view.
2.中介者绑定是实例对实例的,也就是说一个view一定是对应一个mediator,如果有多个view那么一定有多个mediator。


继续另外一个扩展:

The context extension

MVCSContext包括
EventDispatcher(事件分发),
InjectionBinder(注入绑定),
MediationBinder(中介绑定),
CommandBinder(命令绑定)。


可以重新将CommandBinder 绑定到SinalCommandBinder。 命令和中介依托注入,context以为命令和中介的绑定提供关联。

建立一个项目需要从重新定义MVCSContext或者Context,一个app也可以包含多个Contexts,这样可以使你的app更高的模块化,因此,一个app可以独立的设计为聊天模块,社交模块,最终他们会整合到一起成为一个完整的app。





Unity StrangeIoC(七)



strangeioc第三大部分:3.MVCSContext

这一部分讲的是如何使用MVCSContext创建一个app.
MVCSContext式通过使用strangeioc的方式,将所有的小的模块/架构,整合到一个易用的包中。它是以mvcs(s meaning service)的架构来设计的。

1.app的入口是一个monobehavior来扩展的mvcscontext。
2.用mvcs的子类来执行各种绑定。
3.dispatcher(分发器)可以让你在整个app中发送时间,在mvcscontext中它们发送的是TmEvents,你可以重写context来使用signal(消息)的方式发送。
4.commands(命令)会被IEvents或者Signal触发,触发之后会执行一段逻辑。
5.model存储状态。
6.services与app之外的部分通信(比如接入facebook)。





版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/y1196645376/article/details/52746251

智能推荐

React学习记录-程序员宅基地

文章浏览阅读936次,点赞22次,收藏26次。React核心基础

Linux查磁盘大小命令,linux系统查看磁盘空间的命令是什么-程序员宅基地

文章浏览阅读2k次。linux系统查看磁盘空间的命令是【df -hl】,该命令可以查看磁盘剩余空间大小。如果要查看每个根路径的分区大小,可以使用【df -h】命令。df命令以磁盘分区为单位查看文件系统。本文操作环境:red hat enterprise linux 6.1系统、thinkpad t480电脑。(学习视频分享:linux视频教程)Linux 查看磁盘空间可以使用 df 和 du 命令。df命令df 以磁..._df -hl

Office & delphi_range[char(96 + acolumn) + inttostr(65536)].end[xl-程序员宅基地

文章浏览阅读923次。uses ComObj;var ExcelApp: OleVariant;implementationprocedure TForm1.Button1Click(Sender: TObject);const // SheetType xlChart = -4109; xlWorksheet = -4167; // WBATemplate xlWBATWorksheet = -4167_range[char(96 + acolumn) + inttostr(65536)].end[xlup]

若依 quartz 定时任务中 service mapper无法注入解决办法_ruoyi-quartz无法引入ruoyi-admin的service-程序员宅基地

文章浏览阅读2.3k次。上图为任务代码,在任务具体执行的方法中使用,一定要写在方法内使用SpringContextUtil.getBean()方法实例化Spring service类下边是ruoyi-quartz模块中util/SpringContextUtil.java(已改写)import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.s..._ruoyi-quartz无法引入ruoyi-admin的service

CentOS7配置yum源-程序员宅基地

文章浏览阅读2w次,点赞10次,收藏77次。yum,全称“Yellow dog Updater, Modified”,是一个专门为了解决包的依赖关系而存在的软件包管理器。可以这么说,yum 是改进型的 RPM 软件管理器,它很好的解决了 RPM 所面临的软件包依赖问题。yum 在服务器端存有所有的 RPM 包,并将各个包之间的依赖关系记录在文件中,当管理员使用 yum 安装 RPM 包时,yum 会先从服务器端下载包的依赖性文件,通过分析此文件从服务器端一次性下载所有相关的 RPM 包并进行安装。_centos7配置yum源

智能科学毕设分享(算法) 基于深度学习的抽烟行为检测算法实现(源码分享)-程序员宅基地

文章浏览阅读828次,点赞21次,收藏8次。今天学长向大家分享一个毕业设计项目毕业设计 基于深度学习的抽烟行为检测算法实现(源码分享)毕业设计 深度学习的抽烟行为检测算法实现通过目前应用比较广泛的 Web 开发平台,将模型训练完成的算法模型部署,部署于 Web 平台。并且利用目前流行的前后端技术在该平台进行整合实现运营车辆驾驶员吸烟行为检测系统,方便用户使用。本系统是一种运营车辆驾驶员吸烟行为检测系统,为了降低误检率,对驾驶员视频中的吸烟烟雾和香烟目标分别进行检测,若同时检测到则判定该驾驶员存在吸烟行为。进行流程化处理,以满足用户的需要。

随便推点

STM32单片机示例:多个定时器同步触发启动_stm32 定时器同步-程序员宅基地

文章浏览阅读3.7k次,点赞3次,收藏14次。多个定时器同步触发启动是一种比较实用的功能,这里将对此做个示例说明。_stm32 定时器同步

android launcher分析和修改10,Android Launcher分析和修改9——Launcher启动APP流程(转载)...-程序员宅基地

文章浏览阅读348次。出处 : http://www.cnblogs.com/mythou/p/3187881.html本来想分析AppsCustomizePagedView类,不过今天突然接到一个临时任务。客户反馈说机器界面的图标很难点击启动程序,经常点击了没有反应,Boss说要优先解决这问题。没办法,只能看看是怎么回事。今天分析一下Launcher启动APP的过程。从用户点击到程序启动的流程,下面针对WorkSpa..._回调bubbletextview

Ubuntu 12 最快的两个源 个人感觉 163与cn99最快 ubuntu安装源下包过慢_un.12.cc-程序员宅基地

文章浏览阅读6.2k次。Ubuntu 12 最快的两个源 个人感觉 163与cn99最快 ubuntu下包过慢 1、首先备份Ubuntu 12.04源列表 sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup (备份下当前的源列表,有备无患嘛) 2、修改更新源 sudo gedit /etc/apt/sources.list (打开Ubuntu 12_un.12.cc

vue动态路由(权限设置)_vue动态路由权限-程序员宅基地

文章浏览阅读5.8k次,点赞6次,收藏86次。1.思路(1)动态添加路由肯定用的是addRouter,在哪用?(2)vuex当中获取到菜单,怎样展示到界面2.不管其他先试一下addRouter找到router/index.js文件,内容如下,这是我自己先配置的登录路由现在先不管请求到的菜单是什么样,先写一个固定的菜单通过addRouter添加添加以前注意:addRoutes()添加的是数组在export defult router的上一行图中17行写下以下代码var addRoute=[ { path:"/", name:"_vue动态路由权限

JSTL 之变量赋值标签-程序员宅基地

文章浏览阅读8.9k次。 关键词: JSTL 之变量赋值标签 /* * Author Yachun Miao * Created 11-Dec-06 */关于JSP核心库的set标签赋值变量,有两种方式: 1.日期" />2. 有种需求要把ApplicationResources_zh_CN.prope

VGA带音频转HDMI转换芯片|VGA转HDMI 转换器方案|VGA转HDMI1.4转换器芯片介绍_vga转hdmi带音频转换器,转接头拆解-程序员宅基地

文章浏览阅读3.1k次,点赞3次,收藏2次。1.1ZY5621概述ZY5621是VGA音频到HDMI转换器芯片,它符合HDMI1.4 DV1.0规范。ZY5621也是一款先进的高速转换器,集成了MCU和VGA EDID芯片。它还包含VGA输入指示和仅音频到HDMI功能。进一步降低系统制造成本,简化系统板上的布线。ZY5621方案设计简单,且可以完美还原输入端口的信号,此方案设计广泛应用于投影仪、教育多媒体、视频会议、视频展台、工业级主板显示、手持便携设备、转换盒、转换线材等产品设计上面。1.2 ZY5621 特性内置MCU嵌入式VGA_vga转hdmi带音频转换器,转接头拆解

推荐文章

热门文章

相关标签