Delphiman
Delphiman

Reputation: 373

Idea about creating class structure

I have a framework that I developed with several classes and components. I would like to create a main object with access to the entire framework so that all developers can access the methods from a single location.

Example:

MyApp.Framework.DataBase
MyApp.Framework.DateUtils
MyApp.Framework.Users
MyApp.Framework.System

The object MyApp maps entire framework and all developers have full access at any time.

The main question is to create a structure that is robust and easy to expand. After a while I would include a structure of functions and methods of the products of our company.

Example:

MyApp.Blog.    (functions about Blog product)
MyApp.WebDocs. (functions WebDocs product)

More example about class:

TMyAppBase = Class
Private
  Function GetDatabase: TDataBaseClass;
  Function GetUsers: TSystemUsersClass;
  Function GetForms: TFormManager;
Public
  Constructor Create; Virtual;
  Destructor Destroy; Override;
  Property Database: TDataBaseClass Read GetDatabase;
  Property Users: TSystemUsersClass Read GetUsuarios;
  Property Forms: TFormManager Read GetForms;
End;

Using this class:

var
  LMyApp: TMyAppBase 

begin
  ShowMessage(LMyApp.Users.ActiveUserName);
end;

Would that be friends, I would like if possible ideas from yours. My intention its create a single and expansive structure.

Upvotes: 1

Views: 464

Answers (2)

teran
teran

Reputation: 3234

As I've already wrote in my comment, I think in this case it is a good idea to use one main Service (main class, singleton) wich can provide you access to other services. All your modules have unique ID (TGUID). At the beginning of program execution they should register themselves in main service.
for example. main service unit:

unit AppServices;

interface
uses generics.collections, rtti;
type
    // Unique ID Attribute for services
    ServiceIDAttribute = class(TCustomAttribute)
      strict private
        FId : TGUID;
      public
        constructor Create(ServiceID: string);
        property ID : TGUID read FId;
    end;

    //Services Base class
    TCustomAppService = class(TObject)
      strict protected
      public
    end;

    // Main Service Object
    TAppServices = class(TObject)
      strict private
       class var
        FServices : TObjectDictionary<TGUID, TCustomAppService>;
       var
      public
        class constructor Create();
        class destructor Destroy();
        class procedure RegisterService(aService : TCustomAppService);
        class function QueryService(ServiceID : TGUID):TCustomAppService;
    end;

here class constructor & destructor simply creates and frees FServices Dictionary. QueryService method returns Service by its unique ID:

class function TAppServices.QueryService(ServiceID: TGUID): TCustomAppService;
begin
    result := nil;
    if FServices.ContainsKey(ServiceID) then
        result := FServices[ServiceID];
end;

Method RegisterService extracts RTTI Attribute (ServciceIDAttribute) from parameter's class name and adds this pair (id-service) to dictionary:

class procedure TAppServices.RegisterService(aService: TCustomAppService);
var ctx : TRttiContext;
    st : TRttiType;
    a : TCustomAttribute;
    id : TGUID;
begin
    ctx := TRttiContext.Create();
    try
        st := ctx.GetType(aService.ClassType);
        for a in st.GetAttributes() do begin
            if not (a is ServiceIDAttribute) then
                continue;
            id := ServiceIDAttribute(a).ID;

            FServices.AddOrSetValue(id, aService);
            break;
        end;
    finally
        ctx.Free();
    end;
end;

now, about end-services. For example UserManager unit:

unit UserManager;

interface
uses AppServices;

const
    SID_UserManager : TGUID = '{D94C9E3A-E645-4749-AB15-02631F21EC4E}';
type
    [ServiceID('{D94C9E3A-E645-4749-AB15-02631F21EC4E}')]
    TUserManager = class(TCustomAppService)
      strict private
        FActiveUserName: string;
      public
        property ActiveUserName: string read FActiveUserName;
    end;


implementation


initialization
    TAppServices.RegisterService(TUserManager.Create());
end.

now we can test our code:

procedure TestApp();
var uMgr :TUserManager;
    dbMgr : TDBmanager;
begin
    dbMgr := TAppServices.QueryService(SID_DBManager) as TDBManager;
    if dbMgr.Connected then
         writeln('connected!')
    else writeln('not connected');

    uMgr := TAppServices.QueryService(SID_UserManager) as TUserManager;
    writeln('Active user: ', uMgr.ActiveUserName);
end;

summary:
TAppServices is the main object, wich provides access to any service in App. It knows nothing about end-services, so it has no dependencies. you can change its implementation as you wish. You may have as many TCustomAppService class descendants as you need. When you add new service to application, you shouldn't change TAppServices class interface or implementation.

Upvotes: 2

Jens M&#252;hlenhoff
Jens M&#252;hlenhoff

Reputation: 14883

You don't have to create a class for this.

Just create a unit named MyApp.Framework.DataBase and so on. Delphi supports dots in units which makes it possible to create "namespaces".

Delphi even auto completes when you start typing Myapp. in a uses list.

In addition you can create a class TDataBase with static methods that you can call with TDataBase.Method to organize simple functions/procedures in a common scope.

Upvotes: 2

Related Questions