Creando una architecture de software de acoplamiento flexible / escalable

Llevo semanas investigando esto. Actualmente estoy diseñando un diseño de architecture poco acoplado utilizando el método de n niveles (3 capas) y el enfoque de diseño de fábrica. Mi objective es colocar la lógica de negocios de cada cliente (ClientA.DLL, ClientB.DLL) en espacios de nombres separados para que el proyecto se amplíe, lo que significa que puedo modificar / eliminar / agregar la lógica de negocios de un cliente específico sin afectar a los demás, porque son No dependen unos de otros. Luego invoco los espacios de nombres / clase del cliente utilizando el identificador único del cliente (un valor de cadena que se mantiene en la base de datos) a través del espacio de nombres de Factory. Factory.DLL también oculta la lógica por cliente, mientras que BusinessAbstract.DLL sirve como el diseño o la plantilla que las clases por cliente usarán.

Aquí está la solución del proyecto:

texto alternativo

Y aquí está el código real:

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"; } } } 

Implementación de ClientA de la 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"; } } } 

La fábrica

Factory.DLL

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

Ejemplo de implementación en el nivel de presentación

el sitio web

  protected void Page_Load(object sender, EventArgs e) { // invoke Member class using String hardcode Member obj = Invoker.GetMemberInstance("ClientA"); Response.Write(obj.GetClientBLL()); //prints clientA method obj = Invoker.GetMemberInstance("ClientB"); Response.Write(obj.GetClientBLL()); //prints clientB method } 

Y también notará que tengo una carpeta DAL en cada una de las DLL del cliente, así como la DLL AbstractBusinessRule, porque también quiero escalar la capa DAL y usar la estructura de capa “UI-BLL-DAL”.

Cualquier comentario / sugerencia sobre este diseño son bienvenidos. Espero aportes sobre cómo puedo mejorar esta estructura. Gracias por adelantado.

Lo único que veo, y simplemente me estoy perdiendo esto al ver su publicación, pero no veo una definición de interfaz DAL o una capa de abstracción que la separe de su BL de la forma en que su BL se abstrae de su presentación.

Esto es importante porque le brinda la flexibilidad en el futuro para crear una nueva capa de negocios con los mismos datos sin tener que volver a escribir el DAL, o reemplazar su base de datos con archivos / simulacros de CSV planos en pruebas unitarias / un servicio web de soap mantenido por terceros. Respuesta, o cualquier otra cosa podría ser un mejor mecanismo de almacenamiento de datos en el futuro.

Usted tiene una violación básica de la separación de preocupaciones / Principio de responsabilidad única: Sus objetos comerciales conocen su almacenamiento.

La capa de datos de la architecture de 3 niveles debe ser responsable de las operaciones de CRUD y debe consultarse para conocer las instancias de los objetos que necesitan los consumidores. Algo como esto:

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

Esto permite que la capa empresarial se centre en la implementación y mantiene fuera de ello las preocupaciones de persistencia. Si la capa de presentación necesita un nuevo objeto de negocio (para su creación), le pide la capa de datos.

Mi primer comentario sería que sus nombres deben ser mucho más descriptivos. No es obvio en absoluto lo que realmente hace su progtwig al observar el esquema de la solución. Si le da nombres significativos a sus clases de clientes y su área de trabajo, será un paso en la dirección correcta.

Esta pregunta salió demasiado amplia, no hay un enfoque único para todos.

Personalmente, basar los puntos de extensión en agregar clases y herencia sin un caso real que se beneficie fuertemente de esto es algo que he visto que termina en una gran complejidad en general.

Es muy difícil decirlo con la cantidad de información proporcionada, pero considere la alternativa de usar un enfoque más basado en configuración / no significa archivos de configuración, solo configuraciones que se pasan al sistema.

Puede tener un conjunto de reglas básicas y una configuración predeterminada que aplica un conjunto de esas reglas a un cliente. Si lo está haciendo en código, al agregar la configuración de un cliente, simplemente puede decir .AddClient (“ClientA”), y solo usará reglas predeterminadas.

Alternativamente, puede especificar las reglas que se aplican a los procesos del cliente al agregar el cliente, lo que puede implicar establecer reglas diferentes o incluso valores de configuración diferentes para ellos.

ClientA puede tener una necesidad que no está incluida en las reglas básicas, luego se puede aplicar una regla de negocio personalizada / código al proceso del cliente.

No trataría de dar el salto hasta un marco tan genérico. En su lugar, mantendría lo anterior centrado en los procesos específicos y exponiendo los puntos de extensión para esos. A medida que trabaje en la solución, deben surgir patrones comunes y luego, si es apropiado (se ve un beneficio real), puede refactorizarlo a algo más general.