سؤال

في دلفي, كنت تريد أن تكون قادرة على خلق الخاصة الكائن المرتبط فئة ، والوصول إليه من جميع الحالات من هذا الفصل.في جافا, كنت استخدم:

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

أو إذا MySharedObject حاجة أكثر تعقيدا التهيئة في جافا يمكنني إنشاء و تهيئة ذلك في ثابت مهيئ كتلة.

(كنت قد خمنت...أنا أعرف بلدي جافا ولكن أنا جديد بالأحرى إلى دلفي...)

على أي حال, أنا لا أريد أن إنشاء مثيل جديد 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 blogged حول دلفي-هاك كنت قد قدمت هذا ، أصبح من جزئين المادة:

  1. هاك#17:الطبقة الظاهرية المتغيرات الجزء الأول
  2. هاك#17:الطبقة الظاهرية المتغيرات الجزء الثاني

نعم, إنها قراءة طويلة ، ولكن مجزية للغاية.

في ملخص, لقد استخدامها في (إهمال) VMT دخول يسمى vmtAutoTable كمتغير.هذه الفتحة في VMT يمكن استخدامها لتخزين أي 4 بايت القيمة, ولكن إذا كنت ترغب في تخزين يمكنك دائما تخصيص سجل مع كافة الحقول التي ترغب بها.

الكلمات الرئيسية التي كنت تبحث عن "الطبقة فار" - يبدأ هذا كتلة من الدرجة المتغيرات في صفك الإعلان.تحتاج إلى نهاية الكتلة مع "فار" إذا كنت ترغب في أن تشمل مجالات أخرى بعد ذلك (وإلا كتلة قد تكون انتهت "خاص", "عمومية", "الإجراء" إلخ محدد).على سبيل المثال

(تحرير:أنا إعادة قراءة السؤال و انتقلت مرجع في 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;

أنا لcurently استخدامه لبناء ووحدانية الكائنات.

ما أريد القيام به (خاصة فئة ثابت) ، أبرع الحل التي يمكن أن تأتي مع (استنادا إلى الردود حتى الآن) هو:

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 أن يسمى من مواضيع متعددة دون يدعو إلى "syncronize"?حتى إذا كان الأمر كذلك ، قد لا تزال سارية
  • هي الطبقة المتغيرات الموضوع في نطاق أو عالمي حقا ؟
  • إذا كان الصف المتغيرات العالمية حقا ، TLogLogger ليس موضوع آمنة ، قد يكون من الأفضل استخدام الوحدة-العالمية threadvar لتخزين TLogLogger (بقدر ما أنا لا أحب استخدام "العالمية" فأر في أي شكل كان) ، على سبيل المثال

كود:

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+} جملة (نور العيون لارس).

قبل الإصدار 7 ، دلفي لم متغيرات ثابتة عليك استخدام متغير عمومي.

لجعله خاص ممكن وضعه في implementation قسم من الوحدة الخاصة بك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top