装饰器模式可以减少编写重复代码的工作量,这里我们使用Microsoft.Extensions.DependencyInjection依赖注入库(使用NugetForUnity安装)实现装饰器模式
实现效果
主要类和接口
Decorator
类:- 包含两个字典
_listA
和_listAAndB
,用于映射命令(Command
)到具体的工作类(WorkA
或WorkB
)。 - 包含两个装饰器类
DecoratorA
和DecoratorB
,用于包装工作类的执行过程。 Test
方法用于测试服务的注入和调用。
- 包含两个字典
Command
枚举:- 定义了两个命令:
Login
和Register
。
- 定义了两个命令:
IWork
接口:- 定义了一个
DoWork
方法,由工作类和装饰器类实现。
- 定义了一个
WorkA
和WorkB
类:- 实现了
IWork
接口,分别执行不同的工作逻辑。
- 实现了
DecoratorA
和DecoratorB
类:- 实现了
IWork
接口,用于在执行工作类的方法前后添加额外的逻辑。
- 实现了
代码解析
1. 服务注入
// 创建服务集合
var collection = new ServiceCollection();
// 添加服务 WorkA、WorkB
collection.AddTransient<WorkA>();
collection.AddTransient<WorkB>();
- 首先创建了一个
ServiceCollection
,用于管理服务的注册和注入。 - 使用
AddTransient
方法将WorkA
和WorkB
注册为瞬态服务。
2. 命令映射和服务注入
foreach (Command command in Enum.GetValues(typeof(Command)))
{
if (_listA.ContainsKey(command))
{
collection.AddKeyedTransient(command, GetWorkA());
}
else if (_listAAndB.ContainsKey(command))
{
collection.AddKeyedTransient(command, GetWorkAAndB());
}
}
- 遍历
Command
枚举,根据命令类型将不同的工作类或装饰器注册到服务集合中。 - 如果命令在
_listA
中,则使用GetWorkA
方法获取装饰器A
。 - 如果命令在
_listAAndB
中,则使用GetWorkAAndB
方法获取装饰器A
和B
。
3. 获取装饰器的方法
Func<IServiceProvider, object?, IWork> GetWorkA()
{
return (p, key) =>
{
var keyImpl = (Command)(key ?? Command.Login);
var type = _listA[keyImpl];
var obj = (IWork)Activator.CreateInstance(type);
var decorator = new DecoratorA(obj);
return decorator;
};
}
Func<IServiceProvider, object?, IWork> GetWorkAAndB()
{
return (p, key) =>
{
var keyImpl = (Command)(key ?? Command.Login);
var type = _listAAndB[keyImpl];
var obj = (IWork)Activator.CreateInstance(type);
var decoratorA = new DecoratorA(obj);
var decoratorB = new DecoratorB(decoratorA);
return decoratorB;
};
}
GetWorkA
方法返回一个委托,用于创建装饰器A
。GetWorkAAndB
方法返回一个委托,用于创建装饰器B
,然后装饰器B
再装饰装饰器A
。
4. 装饰器类
class DecoratorA : IWork
{
readonly IWork _owner;
public DecoratorA(IWork owner)
{
_owner = owner;
}
public void DoWork()
{
Debug.Log("<color=red>DecoratorA Start</color>");
try
{
_owner.DoWork();
}
finally
{
Debug.Log("<color=red>DecoratorA End</color>");
}
}
}
class DecoratorB : IWork
{
readonly IWork _owner;
public DecoratorB(IWork owner)
{
_owner = owner;
}
public void DoWork()
{
Debug.Log("<color=yellow>DecoratorB Start</color>");
try
{
_owner.DoWork();
}
finally
{
Debug.Log("<color=yellow>DecoratorB End</color>");
}
}
}
DecoratorA
和DecoratorB
类分别在执行工作类的方法前后输出日志。DecoratorB
包装了DecoratorA
,而DecoratorA
包装了实际的工作类。
5. 测试代码
var provider = collection.BuildServiceProvider();
var workA = provider.GetRequiredKeyedService<IWork>(Command.Login);
workA.DoWork();
var workB = provider.GetRequiredKeyedService<IWork>(Command.Register);
workB.DoWork();
- 构建服务提供者
provider
。 - 分别获取
Login
和Register
命令对应的服务实例,并调用DoWork
方法。
完整代码
#nullable enable
using Microsoft.Extensions.DependencyInjection;
public class Decorator
{
enum Command
{
Login,
Register,
}
readonly Dictionary<Command, Type> _listA = new()
{
{ Command.Login, typeof(WorkA) },
};
readonly Dictionary<Command, Type> _listAAndB = new()
{
{ Command.Register, typeof(WorkB) },
};
interface IWork
{
void DoWork();
}
class WorkA : IWork
{
public void DoWork()
{
Debug.Log("<color=cyan>A DoWork</color>");
}
}
class WorkB : IWork
{
public void DoWork()
{
Debug.Log("<color=cyan>B DoWork</color>");
}
}
public void Test()
{
// 创建服务集合
var collection = new ServiceCollection();
// 添加服务 WorkA、WorkB
collection.AddTransient<WorkA>();
collection.AddTransient<WorkB>();
// 添加服务 DecoratorA、DecoratorB
// 如果是 _listA 中的元素,则使用装饰器 A (A 装饰 Work)
// 如果是 _listAAndB 中的元素,则使用装饰器 A 和 B (B 装饰 A,A 装饰 Work)
foreach (Command command in Enum.GetValues(typeof(Command)))
{
if (_listA.ContainsKey(command))
{
collection.AddKeyedTransient(command, GetWorkA());
}
else if (_listAAndB.ContainsKey(command))
{
collection.AddKeyedTransient(command, GetWorkAAndB());
}
}
// 构建服务提供者
var provider = collection.BuildServiceProvider();
// 测试分别执行 WorkA和WorkB
var workA = provider.GetRequiredKeyedService<IWork>(Command.Login);
workA.DoWork();
var workB = provider.GetRequiredKeyedService<IWork>(Command.Register);
workB.DoWork();
}
/// <summary>
/// 获取A装饰器,A 装饰 Work
/// </summary>
/// <returns></returns>
Func<IServiceProvider, object?, IWork> GetWorkA()
{
return (p, key) =>
{
var keyImpl = (Command)(key ?? Command.Login);
var type = _listA[keyImpl];
var obj = (IWork)Activator.CreateInstance(type);
var decorator = new DecoratorA(obj);
return decorator;
};
}
/// <summary>
/// 获取A、B装饰器,B 装饰 A,A 装饰 Work
/// </summary>
/// <returns></returns>
Func<IServiceProvider, object?, IWork> GetWorkAAndB()
{
return (p, key) =>
{
var keyImpl = (Command)(key ?? Command.Login);
var type = _listAAndB[keyImpl];
var obj = (IWork)Activator.CreateInstance(type);
var decoratorA = new DecoratorA(obj);
var decoratorB = new DecoratorB(decoratorA);
return decoratorB;
};
}
/// <summary>
/// 装饰器 A
/// </summary>
class DecoratorA : IWork
{
readonly IWork _owner;
public DecoratorA(IWork owner)
{
_owner = owner;
}
public void DoWork()
{
Debug.Log("<color=red>DecoratorA Start</color>");
try
{
_owner.DoWork();
}
finally
{
Debug.Log("<color=red>DecoratorA End</color>");
}
}
}
/// <summary>
/// 装饰器 B
/// </summary>
class DecoratorB : IWork
{
readonly IWork _owner;
public DecoratorB(IWork owner)
{
_owner = owner;
}
public void DoWork()
{
Debug.Log("<color=yellow>DecoratorB Start</color>");
try
{
_owner.DoWork();
}
finally
{
Debug.Log("<color=yellow>DecoratorB End</color>");
}
}
}
}