سؤال

في تطبيق دلفي الذي نعمل عليه لدينا بنية كبيرة من الكائنات ذات الصلة.تحتوي بعض خصائص هذه الكائنات على قيم يتم حسابها في وقت التشغيل وأنا أبحث عن طريقة لتخزين النتائج مؤقتًا لإجراء العمليات الحسابية الأكثر كثافة.الطريقة التي أستخدمها هي حفظ القيمة في عضو خاص في المرة الأولى التي يتم حسابها فيها.إليك مثال قصير:

unit Unit1;

interface

type
  TMyObject = class
  private
    FObject1, FObject2: TMyOtherObject;
    FMyCalculatedValue: Integer;
      function GetMyCalculatedValue: Integer;
  public
    property MyCalculatedValue: Integer read GetMyCalculatedValue;
  end;

implementation

  function TMyObject.GetMyCalculatedValue: Integer;
  begin
    if FMyCalculatedValue = 0 then
    begin
      FMyCalculatedValue :=
        FObject1.OtherCalculatedValue + // This is also calculated
        FObject2.OtherValue;
    end;

    Result := FMyCalculatedValue;
  end;

end.

ليس من غير المألوف أن تتغير الكائنات المستخدمة في الحساب ويجب إعادة تعيين القيمة المخزنة مؤقتًا وإعادة حسابها.لقد تناولنا هذه المشكلة حتى الآن باستخدام نمط المراقب:تقوم الكائنات بتنفيذ حدث OnChange حتى يتمكن الآخرون من الاشتراك والحصول على إشعارات عند تغيير القيم المخزنة مؤقتًا وإعادة تعيينها.هذا النهج ناجح ولكن له بعض السلبيات:

  • يستغرق الأمر الكثير من الذاكرة لإدارة الاشتراكات.
  • لا يتم قياسه بشكل جيد عندما تعتمد القيمة المخزنة مؤقتًا على الكثير من الكائنات (قائمة على سبيل المثال).
  • التبعية ليست محددة للغاية (حتى لو كانت قيمة ذاكرة التخزين المؤقت تعتمد فقط على خاصية واحدة، فسيتم إعادة تعيينها أيضًا عند تغيير الخصائص الأخرى).
  • تؤثر إدارة الاشتراكات على الأداء العام ويصعب صيانتها (يتم حذف الكائنات أو نقلها أو ...).
  • ليس من الواضح كيفية التعامل مع الحسابات بالاعتماد على القيم المحسوبة الأخرى.

و أخيرا السؤال:هل يمكنك اقتراح طرق أخرى لتنفيذ القيم المحسوبة المخزنة مؤقتًا؟

هل كانت مفيدة؟

المحلول

في عملي أستخدم جريئة لدلفي التي يمكن أن تديرها غير محدود الهياكل المعقدة للقيم المخزنة مؤقتًا تعتمد على بعضها البعض.عادةً ما يحمل كل متغير جزءًا صغيرًا فقط من المشكلة.في هذا الإطار يسمى السمات المشتقة.مشتقة لأن القيمة لا يتم حفظها في قاعدة البيانات، بل تعتمد فقط على سمات مشتقة أخرى أو سمات ثابتة في قاعدة البيانات.

تتم كتابة الكود الموجود خلف هذه السمة في دلفي كإجراء أو في OCL (لغة تقييد الكائنات) في النموذج.إذا كتبته كرمز دلفي، فيجب عليك الاشتراك في المتغيرات التابعة.لذلك، إذا كانت السمة C تعتمد على A وB، فكلما قام A أو B بتغيير رمز إعادة الحساب، يتم استدعاء C تلقائيًا عند قراءة C.لذلك في المرة الأولى التي تتم فيها قراءة C، يتم قراءة A ويتم قراءة B أيضًا (ربما من قاعدة البيانات).طالما لم يتم تغيير A وB، يمكنك قراءة C والحصول على أداء سريع جدًا.بالنسبة للحسابات المعقدة، يمكن أن يوفر هذا الكثير من وقت وحدة المعالجة المركزية.

الجانب السلبي والأخبار السيئة هي أن Bold لم يعد مدعومًا رسميًا ولا يمكنك شرائه أيضًا.أفترض أنه يمكنك الحصول عليه إذا سألت عددًا كافيًا من الأشخاص، لكنني لا أعرف أين يمكنك تنزيله.في الفترة من 2005 إلى 2006 تقريبًا، كان من الممكن تنزيله مجانًا من بورلاند ولكن لم يعد كذلك.إنه ليس جاهزًا لـ D2009 حيث يتعين على شخص ما نقله إلى Unicode.

خيار آخر هو سابقة بمعنى البِيْئَة مع دوت نت من كائنات قادرة.ECO هو مكون إضافي في Visual Studio.إنه إطار عمل مدعوم له نفس الفكرة والمؤلف مثل Bold for Delphi.تم أيضًا تحسين العديد من الأشياء، على سبيل المثال، يتم استخدام ربط البيانات لمكونات واجهة المستخدم الرسومية.يستخدم كل من Bold وECO نموذجًا كنقطة مركزية مع الفئات والسمات والروابط.يمكن أن تستمر هذه في قاعدة بيانات أو ملف XML.مع الإصدار المجاني من ECO، يمكن أن يحتوي النموذج على 12 فئة كحد أقصى، ولكن كما أتذكر لا توجد حدود أخرى.

يحتوي Bold وECO على أكثر بكثير من السمات المشتقة التي تجعلك أكثر إنتاجية وتسمح لك بالتفكير في المشكلة بدلاً من التفاصيل الفنية لقاعدة البيانات أو في حالتك كيفية تخزين القيم مؤقتًا.مرحبًا بك مع المزيد من الأسئلة حول تلك الأطر!

يحرر:هناك في الواقع التحميل رابط للمستخدمين المسجلين Embarcadero ل جريئة لدلفي بالنسبة لـ D7، قديم جدًا ...أعلم أن هناك تحديثات لـ D2005 وإعلان D2006.

نصائح أخرى

إذا كنت تريد تجنب نمط المراقب، فقد تحاول استخدام أسلوب التجزئة.

ستكون الفكرة هي أن تقوم "بتجزئة" الوسيطات، والتحقق مما إذا كان هذا يتطابق مع "التجزئة" التي تم حفظ الحالة لها.إذا لم يحدث ذلك، فيمكنك إعادة الحساب (وبالتالي حفظ التجزئة الجديدة كمفتاح).

أعلم أنني أجعل الأمر يبدو وكأنني فكرت في الأمر للتو، ولكن في الواقع يتم استخدامه بواسطة برامج معروفة.

على سبيل المثال، سلبيات (بديل Makefile) يقوم بذلك للتحقق مما إذا كان الهدف بحاجة إلى إعادة البناء ويفضل اتباع نهج الطابع الزمني.

لقد استخدمنا SCons لأكثر من عام حتى الآن، ولم نكتشف أبدًا أي مشكلة في الهدف الذي لم تتم إعادة بنائه، لذا فإن التجزئة الخاصة بهم تعمل بشكل جيد!

يمكنك تخزين نسخ محلية من قيم الكائنات الخارجية المطلوبة.يقوم روتين الوصول بعد ذلك بمقارنة النسخة المحلية بالقيمة الخارجية، ولا يقوم بإعادة الحساب إلا عند التغيير.

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

يؤدي هذا إلى زيادة مقدار المساحة التي تحتاجها لكل كائن، ولكنه يزيل نمط المراقب.كما أنه يؤجل كافة العمليات الحسابية حتى تكون هناك حاجة إليها، بدلاً من إجراء العملية الحسابية في كل مرة تتغير فيها معلمة المصدر.آمل أن يكون هذا مناسبًا لنظامك.

unit Unit1;

interface

type
  TMyObject = class
  private
    FObject1, FObject2: TMyOtherObject;
    FObject1Val, FObject2Val: Integer;
    FMyCalculatedValue: Integer;
      function GetMyCalculatedValue: Integer;
  public
    property MyCalculatedValue: Integer read GetMyCalculatedValue;
  end;

implementation

  function TMyObject.GetMyCalculatedValue: Integer;
  begin
    if (FObject1.OtherCalculatedValue <> FObjectVal1)
    or (FObject2.OtherValue <> FObjectVal2) then
    begin
      FMyCalculatedValue :=
        FObject1.OtherCalculatedValue + // This is also calculated
        FObject2.OtherValue;
      FObjectVal1 := FObject1.OtherCalculatedValue;
      FObjectVal2 := Object2.OtherValue;
    end;

    Result := FMyCalculatedValue;
  end;

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