Puzzle 面向服务/切面AOP开发框架 For .Net

AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。

日常的产品开发中最常见的就是数据保存的功能。举例来说,现在有个用户信息数据保存的功能,我们希望在数据保存前对数据进行校验,其中现在能想到的校验就包含数据完整性校验和相同数据是否存在校验。按照传统的OOP(面向对象程序设计),我们需要定义一个IUserDataSaveService(用户数据保存服务接口)以及对应的UserDataSaveServiceImpl(用户数据保存服务实现)。同时为了实现保存前数据校验的功能,需要在服务实现(UserDataSaveServiceImpl)中增加数据校验的代码。虽然我们可以通过增加数据校验接口的方式来降低耦合度,但是造成了代码的维护性不佳(假如以后需要增加其他类型的校验就需要修订现有的校验服务,造成程序的可维护性不佳)。同时在整个系统中也不可能仅有用户数据保存这一种保存服务,一定存在了各种各样不同的实现了同一保存接口(IDataSaveService)的保存服务实现,那么如何让这些保存服务实现能够有机会复用同类的数据校验,并且又能方便快速的实现各自不同的数据校验呢?这就是我开发Puzzle系统的原因,它使用AOP的思想,在面向服务设计的基础上,通过对服务中个各个功能步骤或阶段的分解,实现各个逻辑过程的分离,降低耦合,提高维护性。

讲述Puzzle系统前,我们先了解一下Puzzle系统中的一些概念。

1.首先是领域(Domain)的概念。任何一个特殊的实际应用均可被认为是一个特定的领域。

还是以保存案例进行说明,在系统中最常见的就是用户信息的保存和日志的保存。这时必然会首先定义保存功能的接口(ISaveService),并且分别在用户信息(UserInfoSaveServiceImple)和日志(LogSaveServiceImpl)中进行实现。那么很自然的用户信息(UserInfo)和日志(Log)就会被划分为一个特殊的实际应用场景,也就是领域(Domain)。如下图。

在实际业务系统中,可以根据实际业务情况对领域进行划分,在有条件的情况下,将领域划分的越细、越小,对日后功能的扩展和维护越有帮助。

2.服务的定义与实现(ServiceDefine,ServiceImplement)

使用Puzzle开发有一个基础思路是“一切皆为服务”。任何一个细小的功能都尽可能的定义为服务,从而便于此服务的扩展和被调用。

上例中的ISaveService就是一个服务的定义,而UserInfoSaveServiceImpl就是在UserInfo领域下的ISaveService实现。

简单示例如下:

public interface ISaveService
{
void Save(object value);
} [ServiceClass(typeof(ISaveService),ServiceLifeCycle.SingleGet)]
public class UserInfoSaveServiceImpl:ServiceComponent,ISaveService
{
public void Save(object value)
{
throw new NotImplementedException();
}
}

所有的功能点都需要派生自服务组件类(ServiceComponent),具体原因会在后面提及。

3.事件拦截(EventInterceptor)

既然是面向切面编程,那么必然需要有提供切入程序逻辑的机会和方式。在Puzzle系统中,此功能有接口中定义事件,标准程序逻辑中抛出事件,一个或一组拦截器对抛出的事件进行拦截,从而实现对标准逻辑进行扩展或修改的目的。

Puzzle系统通过对类标记EventInterceptorClassAttribute特性标记来表明这个类是一个拦截器类。(同样拦截器类也需要派生自ServiceComponent)

同时在拦截器内部的拦截方法中,Puzzle系统提供了EventInterceptorAttribute的特性标记来标明这个方法是一个拦截方法。

using System;
using Puzzle; namespace Example.EventInterceptor
{
[EventInterceptorClass]
public class BeforeInterceptor : ServiceComponent
{
[EventInterceptor(typeof(IHelloWorldService), "BeforeShow")]
public void Show(object sender, EventArgs e)
{
System.Console.WriteLine("我先说:)");
}
}
}

如上例:标记了BeforeInterceptor类是一个事件拦截器类,其中的方法Show拦截了IHelloWorldService接口的实现类中抛出的BeforeShow方法。BeforeShow方法的事件参数类型为EventArgs。

具体事例参见后文的“附加事件拦截示例”。

4.领域服务容器(DomainServiceContainer)

有了领域的定义和服务的定义后,就需要了解领域服务容器。从字面上就可以清楚的了解到这个容器是用来存放不同领域下的服务的定义和实现(根据服务的生命周期定义来确定是否缓存实现)。

依然使用前面的例子,当Puzzle系统启动后,Puzzle系统中此时就会存在两个相对独立的领域服务容器,分别是UserInfo和Log。在这两个服务容器中都记录了各自对ISaveService的实现定义。

//从UserInfo领域下获取ISaveService的实现(UserInfoSaveServiceImple)
ISaveService userSaver = ServiceContainer.GetService<ISaveService>("UserInfo");
//从Log领域下获取ISaveService的实现(LogSaveServiceImpl)
ISaveService logSaver = ServiceContainer.GetService<ISaveService>("Log");

5.功能点与功能包(FunctionPoint,FunctionPackage)

在设计时对业务进行不同的领域划分,并且在编码时对与抽象出的服务定义做出了实现后,还需要对于所有的服务进行拼装组合(就想玩拼图游戏一样)。一个服务实现就是一个功能点(FunctionPoint),一个服务领域下的功能点集合就是一个功能包(FunctionPackage)。

不同的系统中会有不同类型的功能点。Puzzle系统使用功能点特性标记(FunctionPointAttribute)来标记不同的功能点类型。

Puzzle系统默认提供了服务类型功能点(ServiceClass)和事件拦截器类型功能点(EventInterceptorClass)

aaarticlea/png;base64,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" alt="" />

功能点特性标记的详细说明和如何创建新的功能点类型会在后面提到。

使用XML文件方式来进行功能包和功能点的定义。

简单的功能包示例如下:

<?xml version="1.0" encoding="utf-8"?>
<FunctionPackage xmlns="http://Puzzle">
<Name>Standard FunctionPackage</Name>
<Domain>Standard</Domain>
<BasePackages />
<Items>
<FunctionPoint>
<Name>HelloWorld</Name>
<AssemblyQualifiedName>Example.ServiceClass.Console.Services.HelloWorldService,Puzzle.Example</AssemblyQualifiedName>
</FunctionPoint>
</Items>
</FunctionPackage>

示例中的功能包定义表示该功能包所属的领域名称为“Standard”,只包含一个名称为HelloWorld的功能点,并且没有引用基础功能包。

Puzzle系统在启动后解析此功能包时会首先查询是否存在名称为“Standard”的DomainServiceContainer,如果没有会首先创建。之后会将HelloWorld功能点的定义放入该领域服务容器中,等待被调用。

6.服务的生命周期(ServiceLifeCycle)

在软件的设计开开发过程中,不可避免的会使用到单例模式(wikipedia)。那么就意味着领域服务容器中的不同服务的生命周期会有所不同。Puzzle系统中使用ServiceLifeCycle枚举标识了服务的生命周期定义。

public enum ServiceLifeCycle
SingleGet 每次获取时重新创建
Singleton 每一领域的服务容器中只存在唯一实例

第二点介绍服务实现时的示例中可以看到UserInfoSaveServiceImpl被标记了ServiceClassAttribute,其中第二个参数为ServiceLifeCycle.SingleGet。此参数标识了UserInfoSaveServiceImpl这个服务实现是在每次创建时均创建新的实例(领域服务容器中不会保留该服务实现的实例,每次获取服务时均重新创建新实例)。如果将其标记为ServiceLifeCycle.Singleton则表示此服务实现的实例在领域服务容器中是一直存在的,直到所有系统被关闭回收(领域服务容器保留该服务实现的实例,每次获取到的实例均为同一个)。

7.Puzzle系统的启动和关闭

Puzzle.Application.Start()

开始运行系统(收集并解析功能包,创建领域服务容器)。

Puzzle.Application.Stop()

关闭系统,并释放系统分配的所有资源。

简单服务实现示例:

以下示例显示了如何创建了一个服务接口及对应的一个服务实现。并且如何通过功能包和功能点的配置使其在Puzzle系统中生效,及如何获取该服务实现。

首先定义服务接口及服务实现。

using System;

namespace Example
{
public interface IHelloWorldSerivce
{
void ShowHelloWorld();
}
} using System;
using Puzzle; namespace Example.Console.Services
{
[ServiceClass(typeof(IHelloWorldSerivce), ServiceLifeCycle.SingleGet)]
public class HelloWorldService : ServiceComponent, IHelloWorldSerivce
{
public void ShowHelloWorld()
{
System.Console.WriteLine("Hello World");
}
}
}

通过功能包的配置向Puzzle说明功能点及其所属的领域。

<?xml version="1.0" encoding="utf-8"?>
<FunctionPackage xmlns="http://Puzzle">
<Name>Standard FunctionPackage</Name>
<Domain>Standard</Domain>
<BasePackages />
<Items>
<FunctionPoint>
<Name>HelloWorld</Name>
<AssemblyQualifiedName>Example.Console.Services.HelloWorldService,Puzzle.Example</AssemblyQualifiedName>
</FunctionPoint>
</Items>
</FunctionPackage>

启动Puzzle系统,通过ServiceContainer获取服务实现。

using System;namespace Example
{
public class Program
{
public static void Main(string[] args)
{
Puzzle.Application.Start();
IHelloWorldService service = Puzzle.ServiceContainer.GetService<IHelloWorldService>("Standard");
service.ShowHelloWorld();
}
}
} // 此示例将输出以下内容:
// Hello World

附加事件拦截的示例:

在前例的基础上,当我们需要在真正的ShowHelloWorld方法进行附加操作时对其进行扩展该如何操作?

通过为实现服务增加可拦截的接口,并定义不同业务需要的拦截器即可实现相应业务需要。

以下示例显示如何在ShowHelloWorld方法输出既定内容之前和之后附加输出其他内容。

首先增加事件的接口定义。

using System;

namespace Example
{
public interface IHelloWorldServiceEventArgs
{
event EventHandler BeforeShow; event EventHandler AfterShow;
}
}

对原有的HelloWorldService进行扩展,使其实现刚刚增加的事件定义。并且在真正输出内容的前后分别抛出对应事件。

using System;
using Puzzle; namespace Example
{
[ServiceClass(typeof(IHelloWorldService), ServiceLifeCycle.SingleGet)]
public class HelloWorldService : ServiceComponent, IHelloWorldService, IHelloWorldServiceEventArgs
{
public event EventHandler BeforeShow; public event EventHandler AfterShow; public void ShowHelloWorld()
{
if (BeforeShow != null)
{
this.BeforeShow(this, new
EventArgs());
}
System.Console.WriteLine("Hello World!"); if (AfterShow != null)
{
this.AfterShow(this, new
EventArgs());
}

}
}
}

此时我们就完成了对原有HelloWorldService的修改。使其有能力有机会在需要的情况下被扩展。

其次分别定义对应BeforeShow和AfterShow的事件拦截器(BeforeInterceptor,AfterInterceptor)。

using System;
using Puzzle; namespace Example.EventInterceptor
{
[EventInterceptorClass]
public class BeforeInterceptor : ServiceComponent
{
[EventInterceptor(typeof(IHelloWorldService), "BeforeShow")]
public void Show(object sender, EventArgs e)
{
System.Console.WriteLine("我先说:)");
}
}
} using System;
using Puzzle; namespace Example.EventInterceptor
{
[EventInterceptorClass]
public class AfterInterceptor : ServiceComponent
{
[EventInterceptor(typeof(IHelloWorldService), "AfterShow")]
public void Show(object sender, EventArgs e)
{
System.Console.WriteLine("我说晚了:(");
}
}
}

接着在原有的功能包配置中增加以上两个事件拦截器的定义

<?xml version="1.0" encoding="utf-8"?>
<FunctionPackage xmlns="http://Puzzle">
<Name>Standard FunctionPackage</Name>
<Domain>Standard</Domain>
<BasePackages />
<Items>
<FunctionPoint>
<Name>HelloWorld</Name>
<AssemblyQualifiedName>Example.EventInterceptor.HelloWorldService,Puzzle.Example</AssemblyQualifiedName>
</FunctionPoint>
<FunctionPoint>
<Name>BeforeInterceptor</Name>
<AssemblyQualifiedName>Example.EventInterceptor.BeforeInterceptor,Puzzle.Example</AssemblyQualifiedName>
</FunctionPoint>
<FunctionPoint>
<Name>AfterInterceptor</Name>
<AssemblyQualifiedName>Example.EventInterceptor.AfterInterceptor,Puzzle.Example</AssemblyQualifiedName>
</FunctionPoint>

</Items>
</FunctionPackage>

最后不用更改原有的服务调用方法,即可发现输出内容有所变化

using System;

namespace Example
{
public class Program
{
public static void Main(string[] args)
{
Puzzle.Application.Start();
IHelloWorldService service = Puzzle.ServiceContainer.GetService<IHelloWorldService>("Standard");
service.ShowHelloWorld();
}
}
} // 原示例将输出以下内容:
// Hello World // 此示例将输出以下内容:
// 我先说:)
// Hello World!
// 我说晚了:(

继承基础功能包中提供的功能点

功能包默认会继承所有其指定的基础功能包中的功能点。

例如,基础功能包BasePackage

<?xml version="1.0" encoding="utf-8"?>
<FunctionPackage xmlns="http://Puzzle">
<Name>BasePackage</Name>
<Domain>Base</Domain>
<BasePackages />
<Items>
<FunctionPoint>
<Name>HelloWorld</Name>
<AssemblyQualifiedName>Example.ServiceClass.Console.Services.HelloWorldService,Puzzle.Example</AssemblyQualifiedName>
</FunctionPoint>
</Items>
</FunctionPackage>

继承基础功能包BasePackage的InheritPackage功能包

<?xml version="1.0" encoding="utf-8"?>
<FunctionPackage xmlns="http://Puzzle">
<Name>InheritPackage</Name>
<Domain>Inherit</Domain>
<BasePackages>
<Name>BasePackage</Name>
</BasePackages>
<Items />
</FunctionPackage>

InheritPackage功能包并未标记任何功能点,只是标记了继承了BasePackage。此时在Puzzle系统中,Inherit领域下将自动包含BasePackage中定义的HelloWorld功能点。

using System;

namespace Example
{
public class Program
{
public static void Main(string[] args)
{
Puzzle.Application.Start();
IHelloWorldService service = Puzzle.ServiceContainer.GetService<IHelloWorldService>("Inherit");
service.ShowHelloWorld();
}
}
} // 示例将输出以下内容:
// Hello World

重写或隐藏基础功能包中提供的功能点

以下示例显示当前功能能包中如何定义功能点来重写或隐藏基础功能包所提供的功能点。

例如:功能包BasePackage中有HelloWorld功能点定义:

<?xml version="1.0" encoding="utf-8"?>
<FunctionPackage xmlns="http://Puzzle">
<Name>BasePackage</Name>
<Domain>Base</Domain>
<BasePackages />
<Items>
<FunctionPoint>
<Name>HelloWorld</Name>
<AssemblyQualifiedName>Example.ServiceClass.Console.Services.HelloWorldService,Puzzle.Example</AssemblyQualifiedName>
</FunctionPoint>
</Items>
</FunctionPackage>

功能包CoverPackage中引用了BasePackage功能包作为基础功能包

<?xml version="1.0" encoding="utf-8"?>
<FunctionPackage xmlns="http://Puzzle">
<Name>CoverPackage</Name>
<Domain>Cover</Domain>
<BasePackages>
<Name>
BasePackage
</Name>
</BasePackages>
<Items>
<FunctionPoint>
<Name>HelloWorld</Name>
<Enable>false</Enable>
<AssemblyQualifiedName>Example.ServiceClass.Console.Services.HelloWorldService,Puzzle.Example</AssemblyQualifiedName>

</FunctionPoint>
</Items>
</FunctionPackage>

功能包CoverPackage中的功能点HelloWorld重写了功能包BasePackage中的功能点HelloWorld,由于功能包CoverPackage中的HelloWorld功能点的Enable属性为false。 表示着领域CoverPackage下将不再提供基础功能包BasePackage提供的功能点HelloWorld。

通过 AssemblyQualifiedName 属性是否相同来确认是否为相同的功能点。

此时可以增加另外一个FunctionPoint节点,写入不同的IHelloWorldService接口的实现的AssemblyQualifiedName,从而实现复写BasePackage中提供的HelloWorldService接口实现的目的。

功能点之间的依赖关系

功能点之间的依赖关系由FunctionPoint对象的Dependency属性进行标记。

Dependency属性记录该功能点依赖的功能点的Name。用来标记其需要在依赖功能点执行完成后执行。

以前文提到过的事件依赖器的例子继续衍生,增加BeforeShow的事件拦截器(BeforeInterceptorInFirst)

using System;
using Puzzle; namespace Example.EventInterceptor
{
[EventInterceptorClass]
public class BeforeInterceptorInFirst : ServiceComponent
{
[EventInterceptor(typeof(IHelloWorldService), "BeforeShow")]
public void Show(object sender, EventArgs e)
{
System.Console.WriteLine("沙发!!");
}
}
}

修改功能包文件,增加BeforeInterceptorInFirst功能点,并将BeforeInterceptor功能点的Dependency标记为BeforeInterceptorInFirst功能点的Name

<?xml version="1.0" encoding="utf-8"?>
<FunctionPackage xmlns="http://Puzzle">
<Name>Standard FunctionPackage</Name>
<Domain>Standard</Domain>
<BasePackages />
<Items>
<FunctionPoint>
<Name>HelloWorld</Name>
<AssemblyQualifiedName>Example.EventInterceptor.HelloWorldService,Puzzle.Example</AssemblyQualifiedName>
</FunctionPoint>
<FunctionPoint>
<Name>BeforeInterceptor</Name>
<Dependency>BeforeInterceptorInFirst</Dependency>
<AssemblyQualifiedName>Example.EventInterceptor.BeforeInterceptor,Puzzle.Example</AssemblyQualifiedName>
</FunctionPoint>
<FunctionPoint>
<Name>AfterInterceptor</Name>
<AssemblyQualifiedName>Example.EventInterceptor.AfterInterceptor,Puzzle.Example</AssemblyQualifiedName>
</FunctionPoint>
<FunctionPoint>
<Name>BeforeInterceptorInFirst</Name>
<AssemblyQualifiedName>Example.EventInterceptor.BeforeInterceptorInFirst,Puzzle.Example</AssemblyQualifiedName>
</FunctionPoint>

</Items>
</FunctionPackage>

可以看到XML文件中功能点定义的顺序并不会影响到功能点在系统中依赖关系的确定。

最后不用更改原有的服务调用方法,即可发现输出内容有所变化

using System;

namespace Example
{
public class Program
{
public static void Main(string[] args)
{
Puzzle.Application.Start();
IHelloWorldService service = Puzzle.ServiceContainer.GetService<IHelloWorldService>("Standard");
service.ShowHelloWorld();
}
}
} // 原示例将输出以下内容:
// 我先说:)
// Hello World!
// 我说晚了:( // 此示例将输出以下内容:
// 沙发!!
// 我先说:)
// Hello World!
// 我说晚了:(

功能点特性标记(FunctionPointAttribute)

前文提到过,所有的功能点均由其对应的功能点特性标记来进行说明。

Puzzle系统在启动时,首先查找所有可用的功能包。在完成查找和整理所有待处理的功能包的依赖关系后,会自动开始顺序解析功能包。

解析功能包前由会首先按照前文提到的功能点之间的依赖关系及功能点的优先级对当前功能包中所有的功能点的依赖关系进行整理,整理完成后顺序解析功能点。

解析功能点时就会首先解析功能点代码中标记的功能点特性标记,根据不同的功能点特性标记中提供的功能点解析器对功能点进行解析。

Puzzle系统在解析功能点时默认将ServiceClass类型的功能点优先级排为最高,其次为EventInterceptor类型的功能点。其他类型功能点优先级为正常。

如果需要在不同的业务系统中按照增加功能点类型,只需要在FunctionPointAttribute基础上增加派生类,并增加对应的IFunctionPointParse实现即可。

由于时间有限,本篇文章和Puzzle系统都暂时还只是一个雏形和只实现了最基础功能的AOP框架,后期还会不间断的进行维护和扩展。欢迎广大看客提出宝贵意见!

Alpha 1.1 版本

Puzzle.7z

PuzzleHelper.7z

Puzzle 面向服务/切面(AOP/IOC)开发框架 For .Net的更多相关文章

  1. Spring框架系列(五)--面向切面AOP

    背景: 当需要为多个不具有继承关系的对象引入一个公共行为,例如日志.权限验证.事务等功能时,如果使用OOP,需要为每个对象引入这些公共 行为.会产生大量重复代码,并且不利用维护.AOP就是为了解决这个 ...

  2. Atitit 面向对象编程(OOP)、面向组件编程(COP)、面向方面编程(AOP)和面向服务编程(SOP)的区别和联系

    Atitit 面向对象编程(OOP).面向组件编程(COP).面向方面编程(AOP)和面向服务编程(SOP)的区别和联系 1. 面向组件编程(COP) 所以,组件比起对象来的进步就在于通用的规范的引入 ...

  3. 面向对象编程(OOP)、面向组件编程(COP)、面向方面编程(AOP)和面向服务编程(SOP)

    http://blog.csdn.net/hjf19790118/article/details/6919265 1.什么是面向对象编程(Object-Oriented Programming)? 面 ...

  4. AOP面向方面(切面)编程

    1.引言 软件开发的目标是要对世界的部分元素或者信息流建立模型,实现软件系统的工程需要将系统分解成可以创建和管理的模块.于是出现了以系统模块化特性的面向对象程序设计技术.模块化的面向对象编程极度极地提 ...

  5. Spring基础(二)_面向切面(AOP)

    面向切面编程 面向切面编程[AOP,Aspect Oriented Programming]:通过预编译方式和运行期间动态代理实现程序功能的统一维护的技术.AOP 是 Spring 框架中的一个重要内 ...

  6. 动态代理的两种方式,以及区别(静态代理、JDK与CGLIB动态代理、AOP+IoC)

    Spring学习总结(二)——静态代理.JDK与CGLIB动态代理.AOP+IoC   目录 一.为什么需要代理模式 二.静态代理 三.动态代理,使用JDK内置的Proxy实现 四.动态代理,使用cg ...

  7. SOA(面向服务的架构)

    前言:SOA(面向服务的架构)是目前企业应用开发过程中普遍采用的技术,基于MVC WebAPI三层分布式框架开发,以此适用于企业信息系统的业务处理,是本文论述的重点.此外,插件技术的应用,富客户端JQ ...

  8. SpringBoot切面Aop的demo简单讲解

    前言 本篇文章主要介绍的是SpringBoot切面Aop的demo简单讲解. SpringBoot Aop 说明:如果想直接获取工程那么可以直接跳到底部,通过链接下载工程代码. 切面(Aop) 一.概 ...

  9. 面向服务架构(SOA)和企业服务总线(ESB)

    http://www.cnblogs.com/shanyou/archive/2008/04/19/1161452.html 学习和研究在企业中实施面向服务架构(SOA),简单回顾SOA和ESB,重点 ...

随机推荐

  1. FreeMarker的基础语法

    FreeMarker语言 FreeMarker语言概述 FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写. FreeMarker被设计用来生成HTML Web ...

  2. 《C#微信开发系列(Top)-微信开发完整学习路线》

    年前就答应要将微信开发的学习路线整理给到大家,但是因为年后回来这段时间学校还有公司那边有很多事情需要兼顾,所以没能及时更新文章.今天特地花时间整理了下,话不多说,上图,希望对大家的学习有所帮助哈. 如 ...

  3. 基于JQuery的获取鼠标进入和离开容器方向的实现

    做动画时,需要判断鼠标进入和退出容器的方向.网上找到的基于JQuery的实现方法,用函数封装了一下,写了一个示例.注意绑定鼠标事件用的是on(),所以JQuery版本需高于1.7. <!DOCT ...

  4. Tomcat 配置详解/优化方案

     转自:http://blog.csdn.net/cicada688/article/details/14451541 Service.xml Server.xml配置文件用于对整个容器进行相关的配置 ...

  5. npm更新到最新版本的方法

    打开命令行工具 npm -v 查看是否是最新版本 如果不是 运行npm i npm g 升级 打开C:\Users\用户名用户目录找到node_modules 文件夹下的npm文件夹,复制一份 打开n ...

  6. 自定义UITableViewCell实现左滑动多菜单功能LeftSwipe

    今天愚人节,小伙们,愚人节快乐! 实现一个小功能,滑动菜单,显示隐藏的功能菜单, 先上图:                       这里尝试用了下使用三个方式来实现了这个功能: 1.使用自定义UI ...

  7. Android中点击隐藏软键盘最佳方法——Android开发之路4

    Android中点击隐藏软键盘最佳方法 实现功能:点击EditText,软键盘出现并且不会隐藏,点击或者触摸EditText以外的其他任何区域,软键盘被隐藏: 1.重写dispatchTouchEve ...

  8. redis持久化RDB和AOF

    Redis 持久化: 提供了多种不同级别的持久化方式:一种是RDB,另一种是AOF. RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot). AO ...

  9. [转].NET Core中的认证管理解析

    本文转自:http://www.cnblogs.com/durow/p/5783089.html 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用 ...

  10. MMORPG大型游戏设计与开发(服务器 AI 事件)

    AI中的事件与场景中的事件大致相同,都是由特定的条件触发的.只不过AI的事件与其他事件不同的是,对于AI的事件往往是根据不同的AI类型,和动态的触发条件下才产生的.其实不管AI多么智能,它对应的触发条 ...