【问题标题】:Creating A Loosely-Coupled / Scalable software architecture创建松耦合/可扩展的软件架构
【发布时间】:2011-04-13 20:43:53
【问题描述】:

我已经研究了好几个星期了。我目前正在使用 n 层(3 层)方法和工厂设计方法设计一个松散耦合架构设计。我的目标是将每个客户端的业务逻辑(ClientA.DLL、ClientB.DLL)放在单独的命名空间中,以便项目扩展,这意味着我可以修改/删除/添加特定客户端的业务逻辑而不影响其他客户,因为它们是不相互依赖。然后我通过 Factory 命名空间使用客户端的唯一标识符(数据库中维护的字符串值)调用客户端的命名空间/类。 Factory.DLL隐藏每个客户端的逻辑,而 BusinessAbstract.DLL 用作每个客户端的布局或模板类将使用。

这里是项目解决方案:

这是实际的代码:

BusinessAbstract.DLL

namespace BusinessAbstract
{
   // the entity / data transfer object
   public class MemberDTO
   {
      public string MemberID { get; set; }
      public string MemberName { get; set; }
    }

   // the interface
   public interface IMaintainable
   {
      void Add();
      void Edit();
      void Delete();
   }

  // the base abstract class, implements the Entity and the Interface
  public abstract class Member : MemberDTO, IMaintainable
  {
    // Implement IMaintanable but change it to abstract
    public abstract void Add();
    public abstract void Edit();
    public abstract void Delete();

    // a method with Database access, get from DAL
    public virtual MemberDTO GetMemberDetails(params object[] args)
    {
        return DAL.MemberDAL.FetchMemberDetails(args);
    }

    public virtual string GetClientBLL()
    {
        return "base's method";
    }
   }
 }

ClientA AbstractBusinessRule 的实现

ClientA.DLL

 namespace ClientA
 {
    public class _Member : BusinessAbstract.Member
   {
       public override void Add()
      {
        throw new NotImplementedException();
      }

      public override void Edit()
      {
        throw new NotImplementedException();
      }

      public override void Delete()
      {
        throw new NotImplementedException();
      }

      public override string GetClientBLL()
      {
        return "ClientA Method";
      }
    }
 }

工厂

Factory.DLL

 public static class Invoker
 { 
     public static T GetMemberInstance<T>(string clientCode)
        where T : Member, IMaintainable
      {
        Type objType = Type.GetType(clientCode + "._Member," + clientCode);
        return (T)Activator.CreateInstance(objType);
      } 
  }

表示层上的示例实现

网站

 protected void Page_Load(object sender, EventArgs e)
 {

    // invoke Member class using String hardcode
    Member obj = Invoker.GetMemberInstance<Member>("ClientA");
    Response.Write(obj.GetClientBLL()); //prints clientA method

    obj = Invoker.GetMemberInstance<Member>("ClientB");
    Response.Write(obj.GetClientBLL()); //prints clientB method

 }

您还会注意到,我在每个客户端 DLL 以及 AbstractBusinessRule DLL 中都有一个 DAL 文件夹,因为我还想缩放 DAL 层并使用层结构“UI-BLL-DAL”。

欢迎任何有关此设计的 cmets/建议。我希望就如何改进这种结构提供意见。提前致谢。

【问题讨论】:

  • 谁能告诉我域对象是否比 DTO 更常见?我只是问,因为我以前从未听说过 DTO,但是当我说域对象时,大多数人都知道我的意思,我认为这就是 DTO 的含义..
  • 是的,我认为这只是域/业务对象或实体的老派名称。它是值对象..
  • DTO == 数据传输对象,但我认为 OP 根本没有这样使用它。特别是考虑到 DTO 通常除了保存要传递的数据之外做的事情不多,所以它不像您将业务逻辑放在那里或从中启动持久性操作。
  • 我只是将它附加到真正的业务对象上,因为您可以看到业务对象(Member)除了持有操作之外,还可以在层之间传递数据,因为它继承了MemberDTO。 ,我会说它有点非正统的方法虽然^^
  • DTO 经常被用作层间的传递;一个示例是视图在 MVVM 中呈现(或传递回模型)的 ViewModel。它是模型中某些数据子集的位桶表示,用于其他目的。

标签: c# .net design-patterns architecture


【解决方案1】:

您基本违反了关注点分离/单一职责原则:您的业务对象知道它们的存储。

3 层架构的数据层应该负责 CRUD 操作,并且应该查询消费者需要的对象实例。像这样的:

Presentation Layer ------- Data Layer
                              ||
                              ||
                       Business Layer

这使业务层可以专注于实现,并将持久性问题排除在外。如果表示层需要一个新的业务对象(用于创建),它会向数据层请求它。

【讨论】:

  • 我对3层架构的理解是Presentation - Business - Data,PL不能直接访问数据层。在我的示例中,DataObject (MemberDTO) 是从 PL 到 DAL 通信的对象,它不需要像您所说的那样创建新的业务对象(用于创建)。感谢您的输入^^
  • 三层架构通常意味着有一个表示层、业务层和数据层。它通常按照您的方式构建,但正如您所看到的,业务层中存在各种关注点,这是迄今为止最关键的部分。您可以放入的代码越少,它就越有可能是正确的。
【解决方案2】:

我的第一条评论是你的名字需要更具描述性。通过查看解决方案大纲,您的程序实际上做了什么并不明显。如果你给你的客户类和你的工作区起有意义的名字,那将是朝着正确方向迈出的一步。

【讨论】:

  • 我认为这些名称只是说明一点的例子。 :)
【解决方案3】:

这个问题太宽泛了,没有一个最适合所有方法的方法。

个人在添加类和继承时基于扩展点而没有从中受益的真实案例,这是我看到的以非常复杂的方式结束的事情。

很难用提供的信息量来判断,但考虑使用更多基于配置的方法的替代方案/并不意味着配置文件,只是传递到系统中的配置。

您可以拥有一组基本规则,以及将一组这些规则应用于客户端的默认配置。如果您在代码中执行此操作,则在添加客户端配置时您可能只需要说 .AddClient("ClientA"),它只会使用默认规则。

或者,您可以在添加客户端时指定适用于客户端进程的规则,这可能涉及为这些设置不同的规则甚至不同的配置值。

ClientA 可能有基本规则中未包含的需求,然后可以将自定义/代码业务规则应用于客户端流程。

我不会尝试一直跳到这样一个通用框架。相反,我会将上述内容集中在特定流程上并为这些流程公开扩展点。当您在解决方案中工作时,应该会出现通用模式,然后如果合适(看到真正的好处),您可以将其重构为更通用的东西。

【讨论】:

    【解决方案4】:

    我唯一看到的东西,而且我在查看您的帖子时错过了这一点,但我没有看到 DAL 接口定义或抽象层将其与您的 BL 分开,就像您的 BL 与您的抽象一样演示文稿。

    这很重要,因为它使您在未来可以灵活地使用相同的数据创建新的业务层,而无需重写 DAL,或在单元测试中用平面 CSV 文件/模拟替换您的数据库/维护第 3 方肥皂网络服务响应,或任何其他可能是未来更好的数据存储机制。

    【讨论】:

    • 是的,DAL 与 BL 紧密耦合,因为客户端在 DAL 中具有不同的实现,并且很难为此做出抽象,因为客户端正因为如此。但我会接受也从 BL 中抽象 DAL 的想法。感谢您的输入^^
    • @CSharpNoob:这正是您需要 DAL 抽象层的原因。这样客户端就可以有不同的 DAL 实现,而不必为不同的 DAL 使用不同的客户端。一个在 DAL 接口上尝试相同操作的客户端将根据您交给该客户端的 DAL 实例执行不同的操作。这允许一个客户端处理多个 DAL 实现。您的紧密耦合将需要针对多个 DAL 实现的多个客户端实现。
    猜你喜欢
    • 1970-01-01
    • 2011-11-08
    • 2020-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-01
    • 2011-02-21
    • 1970-01-01
    相关资源
    最近更新 更多