اشتراکها
مقدمه
وراثت، بین کلاسهای والد (Parent) و فرزند (Child) ارتباط ایجاد میکند. در این مطلب، با یک مثال ساده، نکات مختلفی را بررسی خواهیم کرد.
در ابتدا کلاسهایی را با نام parent و child، به شکل زیر ایجاد میکنیم:
با کامپایل کد فوق، هشدار (نه خطا) زیر توسط ویژوال استودیو صادر خواهد شد:
حال با نمونه سازی کلاسهای فوق، رفتار سازنده و متد Print را بررسی میکنیم:
در قسمت اول نمونه سازی از والد، نکته خاصی وجود ندارد. در ابتدا سازنده و سپس فراخوانی متد Print اتفاق خواهد افتاد.
در قسمت دوم نمونه سازی از فرزند، ابتدا سازنده والد و سپس سازنده فرزند فراخوانی خواهند.
در بخش سوم، یک نمونه فرزند را از نوع والد، ایجاد کردهایم .( () Parent pc=new Child). در این بخش ابتدا سازنده والد و بعد از آن سازنده فرزند، فراخوانی میشود و با فراخوانی متد Print، متد والد اجرا خواهد شد.
استفاده از Virtual و Override
اگر بدنبال این باشیم که در قسمت سوم متد Print فرزند فراخوانی شود، مفاهیم virtual و override به کمک ما خواهند آمد:
با تعریف متد از نوع virtual، امکان تحریف رفتار پیش فرض متد را توسط فرزندها، مهیا خواهیم کرد. فرزندان نیز با override کردن متد والد، پیاده سازی خود را اعمال میکنند.
اگر خروجی کد بالا را با قسمت قبل مقایسه کنید، متوجه خواهید شد که در قسمت سوم فرزند، رفتار متد والد را تحریف/بازنویسی (override) کرده است ( پیاده سازی فرزند اجرا شده است).
سازندههای استاتیک (Static Constructor)
سازندههای استاتیک برای مقدار دهی به دادههای استاتیک و یا انجام عملیاتی که تنها قرار است یکبار انجام شوند مورد استفاده قرار میگیرند. این سازندهها بصورت اتوماتیک قبل از ساخت نمونه و مقداردهی اعضای استاتیک و قبل از سازندههای غیر استاتیک اجرا میشوند.
در بخش سوم در ابتدا سازنده استاتیک فرزند و سپس سازنده استاتیک والد فراخوانی خواهند شد و ترتیب اجرای سایر متدها و سازندهها مثل قبل است.
جمع بندی
* اگر نمونهای از یک فرزند را ایجاد کنیم، ابتدا سازندهی والد فراخوانی خواهد شد و پس از آن سازندهی کلاس فرزند.
* اگر قصد تحریف رفتار متد والد را در فرزندان داریم، میتوانیم این متدها را در کلاس والد بصورت virtual تعریف کنیم.
وراثت، بین کلاسهای والد (Parent) و فرزند (Child) ارتباط ایجاد میکند. در این مطلب، با یک مثال ساده، نکات مختلفی را بررسی خواهیم کرد.
در ابتدا کلاسهایی را با نام parent و child، به شکل زیر ایجاد میکنیم:
public class Parent { public Parent() { Console.WriteLine("Parent Constructor"); } public void Print() { Console.WriteLine("Parent Print"); }
} public class Child : Parent { public Child() { Console.WriteLine("Child Constructor"); } public void Print() { Console.WriteLine("Child Print"); } }
هشدارفوق این نکته را تذکر میدهد که متد Print تعریف شده در کلاس Child، پیاده سازی متد Print را در کلاس والد، مخفی (Hide) میکند. به همین خاطر پیشنهاد میکند که اگر واقعا قصد چنین کاری را داریم (نادیده گرفتن پیاده سازی print کلاس والد) از کلمه کلیدی (keyword) new استفاده کنیم. بدین شکل:
public new void Print() { Console.WriteLine("Child Print"); }
Console.WriteLine("====Parent===="); Parent parent = new Parent(); parent.Print(); Console.WriteLine("====Child===="); Child child = new Child(); child.Print(); Console.WriteLine("====Parent Via Child===="); Parent pc = new Child(); pc.Print();
در قسمت دوم نمونه سازی از فرزند، ابتدا سازنده والد و سپس سازنده فرزند فراخوانی خواهند.
در بخش سوم، یک نمونه فرزند را از نوع والد، ایجاد کردهایم .( () Parent pc=new Child). در این بخش ابتدا سازنده والد و بعد از آن سازنده فرزند، فراخوانی میشود و با فراخوانی متد Print، متد والد اجرا خواهد شد.
استفاده از Virtual و Override
اگر بدنبال این باشیم که در قسمت سوم متد Print فرزند فراخوانی شود، مفاهیم virtual و override به کمک ما خواهند آمد:
public class Parent { public Parent() { Console.WriteLine("Parent Constructor"); } public virtual void Print() { Console.WriteLine("Parent Print"); } } public class Child : Parent { public Child() { Console.WriteLine("Child Constructor"); } public override void Print() { Console.WriteLine("Child Print"); } }
اگر خروجی کد بالا را با قسمت قبل مقایسه کنید، متوجه خواهید شد که در قسمت سوم فرزند، رفتار متد والد را تحریف/بازنویسی (override) کرده است ( پیاده سازی فرزند اجرا شده است).
سازندههای استاتیک (Static Constructor)
سازندههای استاتیک برای مقدار دهی به دادههای استاتیک و یا انجام عملیاتی که تنها قرار است یکبار انجام شوند مورد استفاده قرار میگیرند. این سازندهها بصورت اتوماتیک قبل از ساخت نمونه و مقداردهی اعضای استاتیک و قبل از سازندههای غیر استاتیک اجرا میشوند.
public class Parent { static Parent() { Console.WriteLine("Parent static Constructor"); } public Parent() { Console.WriteLine("Parent Constructor"); } public virtual void Print() { Console.WriteLine("Parent Print"); } } public class Child : Parent { static Child() { Console.WriteLine("Child static Constructor"); } public Child() { Console.WriteLine("Child Constructor"); } public override void Print() { Console.WriteLine("Child Print"); }
جمع بندی
* اگر نمونهای از یک فرزند را ایجاد کنیم، ابتدا سازندهی والد فراخوانی خواهد شد و پس از آن سازندهی کلاس فرزند.
* اگر قصد تحریف رفتار متد والد را در فرزندان داریم، میتوانیم این متدها را در کلاس والد بصورت virtual تعریف کنیم.
الگوی مشاهدهگر یکی از محبوبترین و معروفترین الگوهای برنامه نویسی است که پیاده سازی آن در بسیاری از زبانها رواج یافته است. برای نمونه پیاده سازی این الگو را میتوانید در بسیاری از کتابخانهها (به خصوص GUI) مانند این مطالب (+ + + ) مشاهده کنید. برای اینکه بتوانیم این الگو را خودمان برای اشیاء برنامه خودمان پیاده کنیم، بهتر است که بیشتر با خود این الگو آشنا شویم. برای شروع بهتر است که با یک مثال به تعریف این الگو بپردازیم. مثال زیر نقل قولی از یکی از مطالب این سایت است که به خوبی کارکرد این الگو را برای شما نشان میدهد.
عموما به شیءایی که قرار است وضعیت را مشاهده یا رصد کند، Observer گفته میشود و به شیءایی که قرار است وضعیت آن رصد شود Observable یا Subject گفته میشود.
بد نیست بدانید این الگو یکی از کلیدیترین بخشهای معماری لایه بندی MVC نیز میباشد.
همچنین این نکته حائز اهمیت است که این الگو ممکن است باعث نشتی حافظه هم شود و به این مشکل Lapsed Listener Problem میگویند. یعنی یک listener وجود دارد که تاریخ آن منقضی شده، ولی هنوز در حافظه جا خوش کردهاست. این مشکل برای زبانهای شیءگرایی که با سیستمی مشابه GC پیاده سازی میشوند، رخ میدهد. برای جلوگیری از این حالت، برنامه نویس باید این مشکل را با رجیستر کردنها و عدم رجیستر یک شنوده، در مواقع لزوم حل کند. در غیر این صورت این شنونده بی جهت، یک ارتباط را زنده نگه داشته و حافظهی منبع را به هدر میدهد.
مثال: ما یک کلید داریم که سه کلاس RedLED،GreenLED و BlueLED قرار است آن را مشاهده و وضعیت کلید را رصد کنند.
برای پیاده سازی این الگو، ابتدا یک کلاس انتزاعی را با نام Observer که دارای متدی به نام Update است، ایجاد میکنیم. متغیر از نوع کلاس Observable را بعدا ایجاد میکنیم:
سپس یک کلاس پدر را به نام Observable میسازیم تا آن را به شیء سوئیچ نسبت دهیم:
در کلاس بالا یک لیست از نوع Observerها داریم که در آن، کلید با تغییر وضعیت خود، لیست رصد کنندگانش را مطلع میسازد و دیگر چراغهای LED نیازی نیست تا مرتب وضعیت کلید را چک کنند. متدهای attach و Detach در واقع همان رجیسترها هستند که باید مدیریت خوبی روی آنها داشته باشید تا نشتی حافظه پیش نیاید. در نهایت متد NotifyAllObservers هم متدی است که با مرور لیست رصدکنندگانش، رویداد Update آنها را صدا میزند تا تغییر وضعیت کلید به آنها گزارش داده شود.
حال کلاس Switch را با ارث بری از کلاس Observable مینویسیم:
در کلاس بالا هرجایی که وضعیت کلید تغییر مییابد، متد NotifyAllObservers صدا زده میشود.
برای هر سه چراغ، رنگی هم داریم:
سپس در Main اینگونه مینویسیم:
به طور خلاصه هر سه چراغ به شیء کلید attach شده و با هر بار عوض شدن وضعیت کلید، متدهای Update هر سه چراغ صدا زده خواهند شد. نتیجهی کد بالا به شکل زیر در کنسول نمایش مییابد:
یک لامپ و سوئیچ برق را درنظر بگیرید. زمانیکه لامپ مشاهده میکند سوئیچ برق در حالت روشن قرار گرفتهاست، روشن خواهد شد و برعکس. در اینجا به سوئیچ، subject و به لامپ، observer گفته میشود. هر زمان که حالت سوئیچ تغییر میکند، از طریق یک callback، وضعیت خود را به observer اعلام خواهد کرد. علت استفاده از callbackها، ارائه راهحلهای عمومی است تا بتواند با انواع و اقسام اشیاء کار کند. به این ترتیب هر بار که شیء observer از نوع متفاوتی تعریف میشود (مثلا بجای لامپ یک خودرو قرار گیرد)، نیازی نخواهد بود تا subject را تغییر داد.
عموما به شیءایی که قرار است وضعیت را مشاهده یا رصد کند، Observer گفته میشود و به شیءایی که قرار است وضعیت آن رصد شود Observable یا Subject گفته میشود.
بد نیست بدانید این الگو یکی از کلیدیترین بخشهای معماری لایه بندی MVC نیز میباشد.
همچنین این نکته حائز اهمیت است که این الگو ممکن است باعث نشتی حافظه هم شود و به این مشکل Lapsed Listener Problem میگویند. یعنی یک listener وجود دارد که تاریخ آن منقضی شده، ولی هنوز در حافظه جا خوش کردهاست. این مشکل برای زبانهای شیءگرایی که با سیستمی مشابه GC پیاده سازی میشوند، رخ میدهد. برای جلوگیری از این حالت، برنامه نویس باید این مشکل را با رجیستر کردنها و عدم رجیستر یک شنوده، در مواقع لزوم حل کند. در غیر این صورت این شنونده بی جهت، یک ارتباط را زنده نگه داشته و حافظهی منبع را به هدر میدهد.
مثال: ما یک کلید داریم که سه کلاس RedLED،GreenLED و BlueLED قرار است آن را مشاهده و وضعیت کلید را رصد کنند.
برای پیاده سازی این الگو، ابتدا یک کلاس انتزاعی را با نام Observer که دارای متدی به نام Update است، ایجاد میکنیم. متغیر از نوع کلاس Observable را بعدا ایجاد میکنیم:
public abstract class Observer { protected Observable Observable; public abstract void Update(); }
public class Observable { private readonly List<Observer> _observers = new List<Observer>(); public void Attach(Observer observer) { _observers.Add(observer); } public void Dettach(Observer observer) { _observers.Remove(observer); } public void NotifyAllObservers() { foreach (var observer in _observers) { observer.Update(); } } }
حال کلاس Switch را با ارث بری از کلاس Observable مینویسیم:
public class Switch:Observable { private bool _state; public bool ChangeState { set { _state = value; NotifyAllObservers(); } get { return _state; } } }
برای هر سه چراغ، رنگی هم داریم:
public class RedLED:Observer { private bool _on = false; public override void Update() { _on = !_on; Console.WriteLine($"Red LED is {((_on) ? "On" : "Off")}"); } }
public class GreenLED:Observer { private bool _on = false; public override void Update() { _on = !_on; Console.WriteLine($"Green LED is {((_on) ? "On" : "Off")}"); } }
public class BlueLED:Observer { private bool _on = false; public override void Update() { _on = !_on; Console.WriteLine($"Blue LED is {((_on) ? "On" : "Off")}"); } }
var greenLed=new GreenLED(); var redLed=new RedLED(); var blueLed=new BlueLED(); var switchKey=new Switch(); switchKey.Attach(greenLed); switchKey.Attach(redLed); switchKey.Attach(blueLed); switchKey.ChangeState = true; switchKey.ChangeState = false;
Green LED is On Red LED is On Blue LED is On Green LED is Off Red LED is Off Blue LED is Off
اشتراکها
Ember.js 2.0 منتشر شد
اشتراکها
Deno 2 منتشر شد
اشتراکها
ReSharper Ultimate 2018.1 منتشر شد
اشتراکها
سورس باز شدن MSVC's STL
https://github.com/microsoft/STL is our new repository, containing all of our product source code, a new CMake build system, and a README with more information.
اشتراکها
پیشنهاد طراحی ++C امن
Safe C++ is A new Proposal to Make C++ Memory-Safe
The goal of the Safe C++ proposal is extending C++ by defining a superset of the language that can be used to write code with the strong safety guarantees similarly to code written in Rust. The key to its approach is introducing a new safe context where only a rigorously safe subset of C++ is allowed.
Summary
It’s pretty easy to differentiate use cases for Result and exceptions. Whenever the failure is something you expect and know how to deal with – catch it at the lowest level possible and convert into a Result instance. If you don’t know how to deal with it – let it propagate and interrupt the current business operation. Don’t catch exceptions you don’t know what to do about.