在德尔斐,我希望能够创造一种私人目的相关的一类,并访问它的所有实例。在爪哇,我会使用:

public class MyObject {
    private static final MySharedObject mySharedObjectInstance = new MySharedObject();
}

或者,如果MySharedObject需要更多复杂的初始化,在Java我能实例和进行初始化,在一个静态的初始化程序块。

(你可能已经猜到了...我知道我Java但是我而不是新德尔斐...)

无论如何,我不想化的新MySharedObject每次我来创建一个实例MyObject,但我想要一个MySharedObject可以从每个实例的MyObject.(实际上它的记录,已促使我尝试图这来-我使用的Log4D我想储存TLogLogger一类的变量,每一类具有记录的功能。)

什么是最巧妙的方式来做到像这样的东西在德尔菲?

有帮助吗?

解决方案

这里是我会做的是,使用一个类变量、类程序和初始化框:

unit MyObject;

interface

type

TMyObject = class
   private
     class var FLogger : TLogLogger;
   public
     class procedure SetLogger(value:TLogLogger);
     class procedure FreeLogger;
   end;

implementation

class procedure TMyObject.SetLogger(value:TLogLogger);
begin
  // sanity checks here
  FLogger := Value;
end;

class procedure TMyObject.FreeLogger;
begin
  if assigned(FLogger) then 
    FLogger.Free;
end;

initialization
  TMyObject.SetLogger(TLogLogger.Create);
finalization
  TMyObject.FreeLogger;
end.

其他提示

 TMyObject = class
    private
      class var FLogger : TLogLogger;
      procedure SetLogger(value:TLogLogger);
      property Logger : TLogLogger read FLogger write SetLogger;
    end;

procedure TMyObject.SetLogger(value:TLogLogger);
begin
  // sanity checks here
  FLogger := Value;
end;

注意,此类变量将被写入任何类实例,因此可以将它设置在别的地方代码,通常根据一些条件(类型的记录器等)。

编辑:它也将以同样的所有后裔的类。改变它在一个儿童,它改变了所有后裔的实例。你可能还设立了默认的实例处理。

 TMyObject = class
    private
      class var FLogger : TLogLogger;
      procedure SetLogger(value:TLogLogger);
      function GetLogger:TLogLogger;
      property Logger : TLogLogger read GetLogger write SetLogger;
    end;

function TMyObject.GetLogger:TLogLogger;
begin
  if not Assigned(FLogger)
   then FLogger := TSomeLogLoggerClass.Create;
  Result := FLogger;
end;

procedure TMyObject.SetLogger(value:TLogLogger);
begin
  // sanity checks here
  FLogger := Value;
end;

去年,Hallvard Vassbotn博客有关的一个特尔斐-哈克我已经为此,它成为两个部分的文章:

  1. 哈克第17:虚拟类变量,第一部分
  2. 哈克第17:虚拟类变量,第二部分

是的,这是一个很长的读,但是非常有益的。

总之,我重复使用的(deprecated)VMT项称为vmtAutoTable作为一个变量。这老虎在VMT可以用来存储的任何4字节的价值,但是如果你想商店,你总是可以分配一个记录与所有领域的你可以希望。

关键词是寻找"类var"-这开始的框类变量中你的级宣言》。你需要结束块与"var"如果你想包括其他领域的后(否则这块可以结束时通过一个"私人","公众"、"过程"等说明符).例如:

(编辑:我重新阅读问题和移动基准计入TMyClass-你可不能够编辑的TMySharedObjectClass类你想分享,如果它来自别人的图书馆)

  TMyClass = class(TObject)
  strict private
    class var
      FMySharedObjectRefCount: integer;
      FMySharedObject: TMySharedObjectClass;
    var
    FOtherNonClassField1: integer;
    function GetMySharedObject: TMySharedObjectClass;
  public
    constructor Create;
    destructor Destroy; override;
    property MySharedObject: TMySharedObjectClass read GetMySharedObject;
  end;


{ TMyClass }
constructor TMyClass.Create;
begin
  if not Assigned(FMySharedObject) then
    FMySharedObject := TMySharedObjectClass.Create;
  Inc(FMySharedObjectRefCount);
end;

destructor TMyClass.Destroy;
begin
  Dec(FMySharedObjectRefCount);
  if (FMySharedObjectRefCount < 1) then
    FreeAndNil(FMySharedObject);

  inherited;
end;

function TMyClass.GetMySharedObject: TMySharedObjectClass;
begin
  Result := FMySharedObject;
end;

请注意,上述不线的安全,并有可能是更好的方法的参考计数(例如使用的接口),但这是一个简单的例子,它应该让你开始。注意TMySharedObjectClass可以代替TLogLogger或者任何你喜欢的。

嗯,这是不美丽,但是在德尔斐7:

TMyObject = class
pulic
    class function MySharedObject: TMySharedObject; // I'm lazy so it will be read only
end;

implementation

...

class function MySharedObject: TMySharedObject;
{$J+} const MySharedObjectInstance: TMySharedObject = nil; {$J-} // {$J+} Makes the consts writable
begin
    // any conditional initialization ...
   if (not Assigned(MySharedObjectInstance)) then
       MySharedObjectInstance = TMySharedOject.Create(...);
  Result := MySharedObjectInstance;
end;

我目前使用它建立单的对象。

为什么我想要做的(私人类不变),最巧妙的解决方案我可以拿出(基于反应迄今为止)是:

unit MyObject;

interface

type

TMyObject = class
private
  class var FLogger: TLogLogger;
end;

implementation

initialization
  TMyObject.FLogger:= TLogLogger.GetLogger(TMyObject);
finalization
  // You'd typically want to free the class objects in the finalization block, but
  // TLogLoggers are actually managed by Log4D.

end.

也许有点更面向对象将是这样的:

unit MyObject;

interface

type

TMyObject = class
strict private
  class var FLogger: TLogLogger;
private
  class procedure InitClass;
  class procedure FreeClass;
end;

implementation

class procedure TMyObject.InitClass;
begin
  FLogger:= TLogLogger.GetLogger(TMyObject);
end;

class procedure TMyObject.FreeClass;
begin
  // Nothing to do here for a TLogLogger - it's freed by Log4D.
end;

initialization
  TMyObject.InitClass;
finalization
  TMyObject.FreeClass;

end.

这可能会更有意义,如果有多个这种类的常数。

两个问题我认为,需要回答之前你拿出一个"完美的"溶液..

  • 第一,是否TLogLogger是线的安全。可以同TLogLogger被称为从多个线程 没有 呼吁"同步"?即使如此,如下仍可适用
  • 是类变量线范围内的或真正的全球?
  • 如果类变量是真正全球性的,并TLogLogger是无线的安全,你可能被最好用一个单位的全球threadvar储存TLogLogger(尽管我不喜欢使用"全球"var任何形式),例如:

代码:

interface
type
  TMyObject = class(TObject)
  private
    FLogger: TLogLogger; //NB: pointer to shared threadvar
  public
    constructor Create;
  end;
implementation
threadvar threadGlobalLogger: TLogLogger = nil;
constructor TMyObject.Create;
begin
  if not Assigned(threadGlobalLogger) then
    threadGlobalLogger := TLogLogger.GetLogger(TMyObject); //NB: No need to reference count or explicitly free, as it's freed by Log4D
  FLogger := threadGlobalLogger;
end;

编辑:它似乎这类变量在全球范围内存储,而不是一个实例每线。看看 这个问题 对于细节。

在德尔斐静态变量实现为 可变的种类型的常量 :)

这可能有点误导。

procedure TForm1.Button1Click(Sender: TObject) ;
const
   clicks : Integer = 1; //not a true constant
begin
  Form1.Caption := IntToStr(clicks) ;
  clicks := clicks + 1;
end;

是的,另一种可能性是利用全球变量 implementation 您的部分模块。

这只是工作,如果编译器开关"可转让Consts"接通,在全球范围内,或有 {$J+} 语法(。Lars).

前版本7,Delphi没有静态的变量,你就得使用一个全球性的变量。

让它作为私人成为可能,把它放在 implementation 部分的单元。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top