C#中策略设计模式的正确实现方法
我有一个场景,其中有多个条件,我必须以这样的方式编写代码,它应该开放扩展而不是修改,所以我采用了策略设计模式,下面是我的代码,如果我我走在正确的道路上,需要一些关于编写的代码的指导。
// Is this correct way to call it, how to apply dependency injection?
// You can find this code in the end
BaseOrderProcessing baseOrderProcessing =
new BaseOrderProcessing(
new BaseSubscribe(
new SubscribeService(
Subscribe)));
这是实际代码:
public interface IBaseOrderProcessing
{
void ProcessOrder();
}
public class BaseOrderProcessing : IBaseOrderProcessing
{
private IBaseOrderProcessing _baseOrderProcessing = null;
public BaseOrderProcessing(IBaseOrderProcessing baseOrderProcessing)
{
_baseOrderProcessing = baseOrderProcessing;
}
public virtual void ProcessOrder()
{
_baseOrderProcessing.ProcessOrder();
}
}
public interface ISubscribeService
{
SubscribeType SubscribeType { get; set; }
void ActivateSubscribe();
void UpgradeSubscribe();
}
// Strategy Pattern 1 => Subscribe is one of the "if" condition
public class BaseSubscribe : IBaseOrderProcessing
{
private ISubscribeService _SubscribeService = null;
public BaseSubscribe(ISubscribeService SubscribeService)
{
_SubscribeService = SubscribeService;
}
public void ProcessOrder()
{
if (_SubscribeService.SubscribeType == SubscribeType.ACTIVATE)
_SubscribeService.ActivateSubscription();
if (_SubscribeService.SubscribeType == SubscribeType.UPGRADE)
_SubscribeService.UpgradeSubscription();
}
}
// Writing another class to simplify is correct ?????
public class SubscribeService : ISubscribeService
{
private SubscribeDetails _Subscribedetails = null;
public SubscribeType SubscribeType { get; set; }
public SubscribeService(SubscribeDetails Subscribedetails)
{
_Subscribedetails = Subscribedetails;
SubscribeType = Subscribedetails.SubscribeType;
}
public void ActivateSubscription()
{
// Code to save the Subscribe details in the database
Console.WriteLine(
$"\n\nSubscribe {_Subscribedetails.SubscribeId} for " +
$"{_Subscribedetails.SubscribeName} activated for order Id: {_Subscribedetails.OrderId}" +
$" from {_Subscribedetails.SubscribeStartDate} to {_Subscribedetails.SubscribeEndDate}");
}
public void UpgradeSubscription()
{
// Code to upgrade the Subscribe details in the database
Console.WriteLine(
$"\n\nSubscribe {_Subscribedetails.SubscribeId} for " +
$"{_Subscribedetails.SubscribeName} upgraded for order Id: {_Subscribedetails.OrderId}" +
$" from {_Subscribedetails.SubscribeStartDate} to {_Subscribedetails.SubscribeEndDate}");
}
}
客户端代码:
// Is this correct way to call it, how to apply dependency injection?
IBaseOrderProcessing baseOrderProcessing = null;
SubscribeDetails Subscribe = new SubscribeDetails();
Subscribe.OrderId = Guid.NewGuid();
Subscribe.SubscribeId = Guid.NewGuid();
Subscribe.SubscribeName = "Amazon";
Subscribe.SubscribeStartDate = DateTime.Now;
Subscribe.SubscribeEndDate = DateTime.Now.AddDays(30);
if (option == 1)
Subscribe.SubscribeType = SubscribeType.ACTIVATE;
if (option == 2)
Subscribe.SubscribeType = SubscribeType.UPGRADE;
baseOrderProcessing =
new BaseOrderProcessing(
new BaseSubscribe(
new SubscribeService(
Subscribe)));
I have a scenario wherein there are multiple conditions and I have to write a code in such a way that it should be open for extension and not for modification so I went with the strategy design pattern, below is my code, let me know if I'm on the correct path and need some guidance on the code written.
// Is this correct way to call it, how to apply dependency injection?
// You can find this code in the end
BaseOrderProcessing baseOrderProcessing =
new BaseOrderProcessing(
new BaseSubscribe(
new SubscribeService(
Subscribe)));
Here is the actual code:
public interface IBaseOrderProcessing
{
void ProcessOrder();
}
public class BaseOrderProcessing : IBaseOrderProcessing
{
private IBaseOrderProcessing _baseOrderProcessing = null;
public BaseOrderProcessing(IBaseOrderProcessing baseOrderProcessing)
{
_baseOrderProcessing = baseOrderProcessing;
}
public virtual void ProcessOrder()
{
_baseOrderProcessing.ProcessOrder();
}
}
public interface ISubscribeService
{
SubscribeType SubscribeType { get; set; }
void ActivateSubscribe();
void UpgradeSubscribe();
}
// Strategy Pattern 1 => Subscribe is one of the "if" condition
public class BaseSubscribe : IBaseOrderProcessing
{
private ISubscribeService _SubscribeService = null;
public BaseSubscribe(ISubscribeService SubscribeService)
{
_SubscribeService = SubscribeService;
}
public void ProcessOrder()
{
if (_SubscribeService.SubscribeType == SubscribeType.ACTIVATE)
_SubscribeService.ActivateSubscription();
if (_SubscribeService.SubscribeType == SubscribeType.UPGRADE)
_SubscribeService.UpgradeSubscription();
}
}
// Writing another class to simplify is correct ?????
public class SubscribeService : ISubscribeService
{
private SubscribeDetails _Subscribedetails = null;
public SubscribeType SubscribeType { get; set; }
public SubscribeService(SubscribeDetails Subscribedetails)
{
_Subscribedetails = Subscribedetails;
SubscribeType = Subscribedetails.SubscribeType;
}
public void ActivateSubscription()
{
// Code to save the Subscribe details in the database
Console.WriteLine(
quot;\n\nSubscribe {_Subscribedetails.SubscribeId} for " +
quot;{_Subscribedetails.SubscribeName} activated for order Id: {_Subscribedetails.OrderId}" +
quot; from {_Subscribedetails.SubscribeStartDate} to {_Subscribedetails.SubscribeEndDate}");
}
public void UpgradeSubscription()
{
// Code to upgrade the Subscribe details in the database
Console.WriteLine(
quot;\n\nSubscribe {_Subscribedetails.SubscribeId} for " +
quot;{_Subscribedetails.SubscribeName} upgraded for order Id: {_Subscribedetails.OrderId}" +
quot; from {_Subscribedetails.SubscribeStartDate} to {_Subscribedetails.SubscribeEndDate}");
}
}
Client code:
// Is this correct way to call it, how to apply dependency injection?
IBaseOrderProcessing baseOrderProcessing = null;
SubscribeDetails Subscribe = new SubscribeDetails();
Subscribe.OrderId = Guid.NewGuid();
Subscribe.SubscribeId = Guid.NewGuid();
Subscribe.SubscribeName = "Amazon";
Subscribe.SubscribeStartDate = DateTime.Now;
Subscribe.SubscribeEndDate = DateTime.Now.AddDays(30);
if (option == 1)
Subscribe.SubscribeType = SubscribeType.ACTIVATE;
if (option == 2)
Subscribe.SubscribeType = SubscribeType.UPGRADE;
baseOrderProcessing =
new BaseOrderProcessing(
new BaseSubscribe(
new SubscribeService(
Subscribe)));
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您正在构造的对象需要在构造函数中提供运行时详细信息,并且可能(帖子中的假设)与其他对象(如其本身)共享一个公共接口 - 这不是很好,但也不是悲剧 - 它只是使事情变得复杂。
您还可以应用构建器/抽象工厂模式并配置依赖注入来注入所述构建器/工厂服务,以便客户端可以根据一些运行时数据解析实际需要的实现。
如果可能,您可以尝试在 DI 容器中从头开始完全注册此 (BaseOrderProcessing) 服务,并将其注入为完全配置的服务(如果您不必基于某些运行时输入数据来解析它,但例如您正在从 json 获取配置)启动此应用程序时创建文件。
您还可以重新设计您的服务,以便将其作为未初始化的注入,并通过某种方法向其提供 SubscribeDetails - 这将简化 DI 配置。
You are constructing object that requires runtime details in constructor and possibly (assumption from the post) shares a single common interface with other objects like itself - it's not great, but also not tragic - it just complicates things.
You could apply builder / abstract factory pattern in addition and configure dependency injection to inject said builder / factory service, so that the client could resolve actually needed implementation based on some runtime data.
If possible, you could try to register this (BaseOrderProcessing) service completely from scratch in DI container and inject it as fully configured one if you do not have to resolve it based on some runtime input data but for example you are taking config from a json file while starting this app.
You could also redesign your service so that it will be injected as uninitialized and the
SubscribeDetails
will be given to it by some method - it would simplify DI configuration.