views:

169

answers:

4

Hi Guys, I been researching for weeks about this.. I'm currently designing a loosely-coupled architecture design using n-tier(3 layered) method and factory design approach. My goal is to put each Client's business logic (ClientA.DLL, ClientB.DLL) in separate namespaces so that the project scales out meaning I can modify/remove/add a specific clients business logic without affecting the others because its not dependent to each other. Then I Invoke the client's namespaces/class using the client's unique identifier (a string value that is maintained in the database) via the Factory namespace. The Factory.DLL also hides the per-client logic. While the BusinessAbstract.DLL serve as the Layout or the Template that the per-client's classes will be using.

Here is the project solution.

alt text

and here is the actual code:

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 implementation of the 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";
      }
    }
 }

The Factory

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

Sample implementation on Presentation Tier

the Website

 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

 }

And you'll also notice that I have DAL folder on each of the Client's DLL and the AbstractBusinessRule DLL because I also want to scale the DAL layer. And to also layer the structure UI-BLL-DAL

Any comments/suggestion about this design. I need your input guys on how I can improve this structure. Thanks in advance.

+1  A: 

You've got a basic violation of Separation of Concerns/Single Responsibility Principle: Your business objects know about their storage.

The Data Layer of the 3-tier architecture should be responsible for CRUD operations, and should be queried for instances of the objects consumers need. Something like this:

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

This allows the business layer to focus on implementing, and keeps the persistence concerns out of it. If the Presentation layer needs a new business object (for creation), it asks the data layer for it.

arootbeer
my understanding on 3 tier architecture is Presentation - Business - Data, the PL cant access directly to the data layer. On my example, the DataObject (MemberDTO) is the object that communicates from PL to DAL, it doesnt need to create a new business object(for creation) as what you are saying. thanks for the input ^^
CSharpNoob
3 tier architecture generally means there are a Presentation, Business, and Data layer. It is usually constructed the way you have, but as you can see there is a mixing of concerns within the business layer, which is by far the most critical piece to get right. The less code you can put into something, the more likely it is to be correct.
arootbeer
A: 

My first comment would be that your names need to be much more descriptive. It's not obvious at all what your program actually does by looking at the solution outline. If you give your client classes and your workspace meaningful names it'll be a step in the right direction.

Reinderien
I think the names are just examples to illustrate a point. :)
bzlm
A: 

this question came out too broad, there is not a single best for all approach.

Personally basing extension points in adding classes and inheritance without a real case that strongly benefits from it is something I've seen ending in great complexity all around.

Its very hard to tell with the amount of info provided, but consider the alternative of using a more configuration based approach / don't mean config files, just configurations that are passed into the system.

You can have a set of basic rules, and a default configuration that applies a set of those rules to a client. If you are doing it in code, when adding a client's config you may just say .AddClient("ClientA"), and it'll use only default rules.

Alternatively you can specify the rules that apply to the client's processes when adding the client, which can involve setting different rules or even different configuration values for those.

ClientA can have a need that's not included in the basic rules, then a custom/code business rule can be applied to the client process.

I wouldn't try to make the jump all the way to such a generic framework. Instead I'd keep the above focused on the specific processes and exposing extension points for those. As you work in the solution, common patterns should emerge and then if appropriate (a real benefit is seen) you can refactor it to something more general.

eglasius
+1  A: 

The only thing I see, and I mist just be missing this in looking at your post, but I don't see a DAL interface definition or abstraction layer that seperates it from your BL in the way your BL is abstracted from your presentation.

This is important because it gives you the flexibility in the future to create a new business layer using the same data without having to rewrite the DAL, or replacing your database with flat CSV files/mocks in unit testing/a 3rd party maintained soap web service response, or whatever else might be a better data storage mechanism in the future.

Jimmy Hoffa
YEs the DAL is tightly-coupled to the BL because the clients have different implementation in the DAL, and its hard to make an abstract for this because client's because of that. but I'd take the Idea of also abstracting the DAL from BL. thanks for the input ^^
CSharpNoob
@CSharpNoob: And that's exactly why you need a DAL abstraction layer. So that clients can have different implementations of the DAL, without having to use different clients for different DALs. One client that attemps that same thing on a DAL interface, will do different things depending on the instance of the DAL you handed to that client. This allows one client to work against multiple DAL implementations. Your tight coupling will require multiple client implementations for multiple DAL implementations.
Jimmy Hoffa
thanks Jimmy, I think I have to consider it..
CSharpNoob