سلام! در درس امروز به بررسی موضوع کلاس های تو در تو ادامه خواهیم داد. نوبت به آخرین گروه می رسد - کلاس های داخلی ناشناس در جاوا. بیایید به نمودار خود برگردیم: مانند کلاس های محلی که در سخنرانی گذشته در مورد آنها صحبت کردیم، کلاس های ناشناس زیر مجموعه ای از کلاس های داخلی هستند. آنها همچنین چندین شباهت و تفاوت بین آنها دارند. اما ابتدا، بیایید آن را بفهمیم: چرا آنها در واقع "ناشناس" نامیده می شوند؟ برای انجام این کار، اجازه دهید به یک مثال ساده نگاه کنیم. تصور کنید که ما یک برنامه اصلی داریم که مدام در حال اجراست و کاری انجام می دهد. ما می خواهیم برای این برنامه یک سیستم مانیتورینگ متشکل از چندین ماژول ایجاد کنیم. یک ماژول شاخصهای عملکرد کلی را نظارت میکند و یک گزارش نگه میدارد، دومی خطاها را در گزارش خطا ثبت و ثبت میکند، سومین ماژول فعالیتهای مشکوک را نظارت میکند: به عنوان مثال، تلاشهای دسترسی غیرمجاز و سایر موارد مرتبط با امنیت. از آنجایی که هر سه ماژول اساساً باید از ابتدای برنامه شروع شده و در پس زمینه اجرا شوند، ایده خوبی است که یک رابط مشترک برای آنها ایجاد کنید:
و درس امروز ما به پایان رسیده است! و اگرچه ما آخرین گروه از کلاسهای تودرتو را پوشش دادهایم، هنوز کارمان با این موضوع تمام نشده است. در ادامه در مورد کلاس های تو در تو چه خواهیم خواند؟ قطعا به زودی متوجه خواهید شد! :)
public interface MonitoringSystem {
public void startMonitoring();
}
توسط 3 کلاس خاص اجرا خواهد شد:
public class GeneralIndicatorsMonitoringModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Monitoring of general indicators has started!");
}
}
public class ErrorMonitoringModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Bug Tracking Monitoring Started!");
}
}
public class SecurityModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Security monitoring started!");
}
}
به نظر می رسد که همه چیز مرتب است. ما یک سیستم نسبتاً واضح از چندین ماژول داریم. هر کدام از آنها رفتار خاص خود را دارند. اگر به ماژولهای جدید نیاز داریم، میتوانیم آنها را اضافه کنیم، زیرا رابطی داریم که پیادهسازی آن بسیار آسان است. اما بیایید به این فکر کنیم که سیستم نظارتی ما چگونه کار خواهد کرد. در اصل، ما فقط باید 3 شی - GeneralIndicatorsMonitoringModule
, ErrorMonitoringModule
, SecurityModule
- ایجاد کنیم و startMonitoring()
روی هر یک از آنها یک متد فراخوانی کنیم. یعنی تنها کاری که باید انجام دهید این است که 3 آبجکت بسازید و 1 متد را روی آنها فراخوانی کنید.
public class Main {
public static void main(String[] args) {
GeneralIndicatorsMonitoringModule generalModule = new GeneralIndicatorsMonitoringModule();
ErrorMonitoringModule errorModule = new ErrorMonitoringModule();
SecurityModule securityModule = new SecurityModule();
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
}
}
خروجی کنسول:
Мониторинг общих показателей стартовал!
Мониторинг отслеживания ошибок стартовал!
Мониторинг безопасности стартовал!
و برای چنین کار کوچکی یک سیستم کامل نوشتیم: 3 کلاس و یک رابط! و همه اینها به خاطر 6 خط کد. از طرفی گزینه های ما چیست؟ بله، خیلی جالب نیست که ما چنین کلاس های "یکبار مصرف" نوشتیم. اما چگونه می توانیم این را برطرف کنیم؟ اینجاست که کلاس های داخلی ناشناس به کمک ما می آیند ! در مورد ما به این صورت است:
public class Main {
public static void main(String[] args) {
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Monitoring of general indicators has started!");
}
};
MonitoringSystem errorModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Bug Tracking Monitoring Started!");
}
};
MonitoringSystem securityModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Security monitoring started!");
}
};
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
}
}
بیایید بفهمیم اینجا چه خبر است! به نظر می رسد که ما در حال ایجاد یک شی رابط هستیم:
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Monitoring of general indicators has started!");
}
};
اما مدتهاست که می دانیم ایجاد اشیاء رابط غیرممکن است! درست است، غیرممکن است. در واقع ما این کار را نمی کنیم. لحظه ای که می نویسیم:
MonitoringSystem generalModule = new MonitoringSystem() {
};
در داخل ماشین جاوا موارد زیر اتفاق می افتد:
- یک کلاس جاوا بدون نام ایجاد می شود که
MonitoringSystem
. - کامپایلر با دیدن چنین کلاسی از شما می خواهد که تمام متدهای رابط را پیاده سازی کنید
MonitoringSystem
(ما این کار را 3 بار انجام دادیم). - یک شی از این کلاس ایجاد می شود. به کد توجه کنید:
MonitoringSystem generalModule = new MonitoringSystem() {
};
در پایان یک نقطه ویرگول وجود دارد! او به دلیلی آنجا ایستاده است. ما به طور همزمان یک کلاس را (از طریق پرانتزهای فرفری) اعلام می کنیم و شیء آن را با استفاده از هر یک از سه شیء ما به روش خود ();
یک متد را لغو کرده اند . startMonitoring()
در پایان ما به سادگی این متد را برای هر یک از آنها فراخوانی می کنیم:
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
خروجی کنسول:
Мониторинг общих показателей стартовал!
Мониторинг отслеживания ошибок стартовал!
Мониторинг безопасности стартовал!
همین! ما وظیفه خود را کامل کردیم: سه شی ایجاد کردیم MonitoringSystem
، آن را به سه روش مختلف دوباره تعریف کردیم و سه بار آن را فراخوانی کردیم. هر سه ماژول با موفقیت راه اندازی شده و کار می کنند. در عین حال ساختار برنامه ما بسیار ساده تر شده است! GeneralIndicatorsMonitoringModule
از این گذشته ، ErrorMonitoringModule
اکنون می توان کلاس ها را SecurityModule
به طور کلی از برنامه حذف کرد! ما به سادگی به آنها نیاز نداریم - بدون آنها به خوبی موفق شدیم. اگر هر یک از کلاسهای ماژول ناشناس ما به رفتارهای متفاوتی نیاز دارد، روشهای خاص خود را که بقیه ندارند، میتوانیم به راحتی آنها را اضافه کنیم:
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Monitoring of general indicators has started!");
}
public void someSpecificMethod() {
System.out.println("Specific method for first module only");
}
};
مستندات Oracle یک توصیه خوب دارد : "اگر برای یک بار استفاده به یک کلاس محلی نیاز دارید، از کلاس های ناشناس استفاده کنید." یک کلاس ناشناس یک کلاس داخلی تمام عیار است. بنابراین، به متغیرهای کلاس خارجی، از جمله متغیرهای استاتیک و خصوصی دسترسی دارد:
public class Main {
private static int currentErrorsCount = 23;
public static void main(String[] args) {
MonitoringSystem errorModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Bug Tracking Monitoring Started!");
}
public int getCurrentErrorsCount() {
return currentErrorsCount;
}
};
}
}
آنها چیزی مشترک با کلاس های محلی دارند: آنها فقط در روشی که در آن تعریف شده اند قابل مشاهده هستند. در مثال بالا، هرگونه تلاش برای دسترسی به شی errorModule
خارج از متد main()
با شکست مواجه خواهد شد. و یک محدودیت مهم دیگر که کلاس های ناشناس از "اجداد" خود به ارث برده اند - کلاس های داخلی: یک کلاس ناشناس نمی تواند شامل متغیرها و متدهای ثابت باشد . اگر بخواهیم متد را getCurrentErrorsCount()
از مثال بالا ثابت کنیم، کامپایلر یک خطا ایجاد می کند:
//error! Inner classes cannot have static declarations
public static int getCurrentErrorsCount() {
return currentErrorsCount;
}
اگر بخواهیم یک متغیر استاتیک را اعلام کنیم، همان نتیجه را دریافت می کنیم:
MonitoringSystem errorModule = new MonitoringSystem() {
//error! Inner classes cannot have static declarations!
static int staticInt = 10;
@Override
public void startMonitoring() {
System.out.println("Bug Tracking Monitoring Started!");
}
};
در نهایت می توانم یک ویدیوی عالی با موضوع کلاس های ناشناس به شما توصیه کنم که در آن این موضوع تا حد امکان ساده و واضح توضیح داده شده است :)
GO TO FULL VERSION