使用表达式树,让访问者直接执行“角色”对象的方法
时间:2022-04-29
本文章向大家介绍使用表达式树,让访问者直接执行“角色”对象的方法,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
以前,我们在讨论《业务分析三维度(场景+角色+时间)理论》 的软件设计的时候,对于场景中的访问者,动态附加场景许可的角色,如何通过访问者执行角色方法的问题,采用了下面的实现方式:
Actor.ActAs<IRole>().Function(Para para);
这种方式本质上是将Actor转换成为了IRole接口的实例对象,然后进行方法访问的,但这样就暴露了角色对象,比如可以这样继续使用:
IRole role=Actor.ActAs<IRole>();
role.Fun1();
role.Fun2("abc");
这样看起来的话,role 跟Actor 是2个对象了,总觉得有点割裂。 今天,我们使用表达式树,来实现一个更优美的方案。
首先定义角色对象和访问者对象的接口:
public interface IActor
{
string Name { get; }
}
public interface IRole
{
IActor Actor { get; set; }
}
然后定义一个动物角色接口,它拥有走路和吃东西的本能方法;
public interface IAnimal:IRole
{
void Move();
int Eat(string food);
}
接着实现一个动物角色类:
public class Animal : IAnimal
{
public IActor Actor { get; set; }
#region IAnimal 成员
public void Move()
{
Console.WriteLine("{0} move...",Actor.Name);
}
public int Eat(string food)
{
Console.WriteLine("{0} eat.{1}.", Actor.Name, food);
return 1;
}
#endregion
}
在实际的角色对象中,它是可以访问“访问者”的方法的,比如这里的ActorName
下面,是我们的重点,Actor 访问者类的实现:
class Actor:IActor
{
private List<IRole> roles = new List<IRole>();
public string Name { get; private set; }
public Actor(string name)
{
this.Name = name;
}
public void AddRole(IRole role)
{
roles.Add(role);
role.Actor = this;
}
public TResule ActAs<T, TResule>(Expression<Func<T, TResule>> exp) where T : class
{
//在执行前做一些事情
var lambda = exp.Compile();
TResule result = lambda.Invoke(GetObject<T>());
//在执行后做一些事情
return result;
}
public T GetObject<T>() where T : class
{
foreach (IRole role in roles)
{
if (role is T)
return role as T;
}
return null;
}
}
我们重点来看ActAs 方法,它将把自己转换成指定的角色,然后调用角色的方法,但是参数是 Expression<Func<T, TResule>> ,这就允许我们以非常友好的方式来编码了,还是看看怎么调用这个代码:
Actor man = new Actor("zhagnsan");
man.AddRole(new Animal());//为张三添加动物的本能职责
var result=man.ActAs<IAnimal, int>(a => a.Eat("rice"));
Console.WriteLine("result:{0}",result);
我们在方法里面,用熟悉的方式,调用了动物角色的吃东西方法。
这里是程序输出:
zhagnsan eat.rice.
result:1
相比较文章开头的方式, 这里man.ActAs<IAnimal, int> 直接执行了角色对象的方法,而不给外部人员知晓zhangsan 拥有某个角色对象实例的机会,这样就完成了访问者对于自己角色更好的“封装”。也就是,只有自己才可以执行自己角色的方法,这才是符合真实场景的设计。
-----------分界线------------------------
欢迎加入PDF.NET开源技术团队,做最好最轻最快的框架!
- mysql数据与Hadoop之间导入导出之Sqoop实例
- 如何将mysql数据导入Hadoop之Sqoop安装
- 常见的几种Flume日志收集场景实战
- 教你一步搭建Flume分布式日志系统
- 几十条业务线日志系统如何收集处理?
- 0基础搭建Hadoop大数据处理-编程
- 0基础搭建Hadoop大数据处理-集群安装
- Validation of viewstate MAC failed 解决办法
- springmvc注入类 NoUniqueBeanDefinitionException: No qualifying bean of type [] is defined: expected sin
- springmvc注入类 NoUniqueBeanDefinitionException: No qualifying bean of type [] is defined: expected sin
- idea启动多个tomcat失败
- Log4Net 生成多个文件、文件名累加解决方法
- 【C#|.NET】lock(this)其实是个坑
- SpringMVC过程中@RequestBody接收Json的问题 总是报415
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【JS】666- window.reqeustIdleCallback方法详解
- 一个无聊的宏定义
- windows的Ubuntu子系统ssh和ftp
- 面试官问:如何设计一个安全的对外接口?
- [树莓派公网远程监控]autossh反向代理
- 用 LDSC 计算遗传度以及遗传相关性
- SVG 入门指南(初学者入门必备)
- 快速介绍Python数据分析库pandas的基础知识和代码示例
- CSDN如何自定义一个漂亮的模块
- centeros7安装mysql
- 使用Keras构建具有自定义结构和层次图卷积神经网络(GCNN)
- 给大忙人写的单例模式的八种实现方法
- 在Python中使用Torchmoji将文本转换为表情符号
- 我通过三个故事终于学明白了三种工厂模式
- 《设计模式》系列-SOLID设计原则