首页 > 解决方案 > 教程逻辑与主应用逻辑分离

问题描述

在这里,我们正在开发一个电子邮件客户端软件,它有一个特定的用户界面,我们需要将其传授给用户。

有一些类处理应用程序的逻辑。例如,在项目的主要类之一中有这样的功能:

public void ComposeMessage(string username,string message)
{
    MessageComposer.ComposeMessage(username, message);
}

因此,在上述函数中,我们向用户发送消息。

但在应用程序的另一面;有一个教程阶段。因此,当用户进入应用程序的教程端时,他可以与我们告诉他的应用程序按钮进行交互,但我们不想发送真正的消息。所以我们把上面的函数改成这样:

public void ComposeMessage(string username,string message)
{
    if(!Global.IsTutorial)
        MessageComposer.ComposeMessage(username, message);
}

因此,我们if(!Global.IsTutorial)在它们的主体中添加了许多功能。我们怎样才能避免这种情况呢?我们不想更改教程部分中的函数主体,也不想在我们的项目中添加更多代码和类。我们希望尽可能降低更改。

标签: c#solid-principlesobject-oriented-analysis

解决方案


有很多方法可以实现您想要的,但它们都暗示,首先,您不ComposeMessage直接使用,而是为其创建接口并重构调用者以将其作为依赖项注入:

public interface IMessageComposer
{
    void ComposeMessage(string username, string message);
}

public class MyApp
{
    IMessageComposer messageComposer;

    public MyApp(IMessageComposer messageComposer)
    {
        this.messageComposer = messageComposer;
    }

    public void Foo()
    {
        messageComposer.ComposeMessage(username, message);
    }
}

当您不依赖具体实现并注入依赖项时,您可以将实现更改IMessageComposer为您喜欢的任何内容,而无需实际接触原始MessageComposer' 或MyApp' 代码。

例如,您可以TutorialMessageComposer像这样创建

public class TutorialMessageComposer : IMessageComposer
{
    public void ComposeMessage(string username, string password)
    {
        Console.WriteLine("Tutorial mode!");
    }
}

RoutingMessageComposer装饰器将检查当前模式并调用正确的作曲家

public class RoutingMessageComposer : IMessageComposer
{
    IMessageComposer composer;
    IMessageComposer tutorialComposer;

    public RoutingMessageComposer(IMessageComposer composer, IMessageComposer tutorialComposer)
    {
        this.composer = composer;
        this.tutorialComposer = tutorialComposer;
    }

    public void ComposeMessage(string username, string message)
    {
        if (Global.IsTutorial)
            tutorialComposer.ComposeMessage(username, message);
        else
            composer.ComposeMessage(username, message);    
    }
}

RoutingMessageComposer一切准备就绪后,你只需要坚持MyApp

var app = new MyApp(new RoutingMessageComposer(new MessageComposer(), new TutorialMessageComposer())); 

推荐阅读