سلام! در سخنرانی امروز با مفهوم « تغییرکنندههای دسترسی » آشنا میشویم و نمونههایی از کار با آنها را بررسی میکنیم. اگرچه کلمه "بیایید آشنا شویم" کاملاً صحیح نخواهد بود: شما قبلاً با بسیاری از آنها در سخنرانی های قبلی آشنا هستید. در هر صورت، بیایید حافظه خود را در مورد چیز اصلی تازه کنیم. اصلاح کننده های دسترسی اغلب کلمات کلیدی هستند که سطح دسترسی به بخش های مختلف کد شما را تنظیم می کنند. چرا "اغلب"؟ چون یکی از آنها به صورت پیش فرض تنظیم شده است و با کلمه کلیدی نشان داده نمی شود :) در مجموع چهار تغییر دهنده دسترسی در جاوا وجود دارد. ما آنها را به ترتیب از سخت ترین تا "نرم ترین" فهرست می کنیم:
- خصوصی؛
- حفاظت شده؛
- پیش فرض (بسته قابل مشاهده)؛
- عمومی
اصلاح کننده خصوصی
Private
- محدودترین اصلاح کننده دسترسی. دید داده ها و متدها را در یک کلاس محدود می کند. شما این اصلاح کننده را از سخنرانی در مورد گیرنده ها و ستترها می شناسید. این مثال را به خاطر دارید؟
public class Cat {
public String name;
public int age;
public int weight;
public Cat(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
public Cat() {
}
public void sayMeow() {
System.out.println("Meow!");
}
}
public class Main {
public static void main(String[] args) {
Cat cat = new Cat();
cat.name = "";
cat.age = -1000;
cat.weight = 0;
}
}
ما در یکی از مقالات قبلی به آن نگاه کردیم. در اینجا ما یک اشتباه جدی مرتکب شدیم: ما داده های خود را باز کردیم، در نتیجه برنامه نویسان همکار به فیلدهای کلاس دسترسی مستقیم داشتند و مقادیر آنها را تغییر می دادند. علاوه بر این، این مقادیر بدون بررسی اختصاص داده شد، در نتیجه در برنامه ما امکان ایجاد گربه با سن -1000 سال، نام "" و وزن 0 وجود دارد. برای حل این مشکل، ما گیرنده ها و تنظیم کننده ها استفاده می شود و همچنین دسترسی محدود به داده ها با استفاده از یک اصلاح کننده private
.
public class Cat {
private String name;
private int age;
private int weight;
public Cat(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
public Cat() {
}
public void sayMeow() {
System.out.println("Meow!");
}
public String getName() {
return name;
}
public void setName(String name) {
// checking the input parameter
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
// checking the input parameter
this.age = age;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
// checking the input parameter
this.weight = weight;
}
}
در واقع، محدود کردن دسترسی به فیلدها و پیاده سازی getters-setter رایج ترین نمونه استفاده private
در کار واقعی است. یعنی پیاده سازی کپسوله سازی در یک برنامه هدف اصلی این اصلاح کننده است. به هر حال، این نه تنها در زمینه ها صدق می کند. تصور کنید که در برنامه شما روشی وجود دارد که عملکردهای بسیار پیچیده ای را پیاده سازی می کند. برای اینکه به این به عنوان مثال برسیم... فرض کنید روش شما readDataFromCollider()
یک آدرس با داده به عنوان ورودی می گیرد، داده ها را از برخورد دهنده بزرگ هادرون در قالب بایت می خواند، این داده ها را به متن تبدیل می کند، آن را به یک فایل می نویسد و آن را چاپ می کند. حتی توضیحات روش هم ترسناک به نظر می رسد، چه برسد به کد :) برای افزایش خوانایی کد، خوب است منطق پیچیده روش را در یک جا ننویسیم، بلکه برعکس، عملکرد را خراب کنیم. به روش های جداگانه به عنوان مثال، این روش readByteData()
وظیفه خواندن داده ها، convertBytesToSymbols()
تبدیل داده های خوانده شده از برخورد دهنده به متن، saveToFile()
ذخیره متن به دست آمده در یک فایل و printColliderData()
چاپ فایل داده ما را بر عهده دارد. این روش readDataFromCollider()
در نهایت بسیار ساده تر خواهد بود:
public class ColliderUtil {
public void readDataFromCollider(Path pathToData) {
byte[] colliderData = readByteData(pathToData);
String[] textData = convertBytesToSymbols(colliderData);
File fileWithData = saveToFile(textData);
printColliderData(fileWithData);
}
public byte[] readByteData(Path pathToData) {
// reads data in bytes
}
public String[] convertBytesToSymbols(byte[] colliderDataInBytes) {
// convert bytes to characters
}
public File saveToFile(String[] colliderData) {
// save the read data to a file
}
public void printColliderData(File fileWithColliderData) {
// print data from file
}
}
با این حال، همانطور که از سخنرانی در مورد رابط ها به یاد دارید، کاربر فقط به رابط نهایی دسترسی پیدا می کند. و 4 روش ما بخشی از آن نیست. آنها کمکی هستند : ما آنها را برای بهبود خوانایی کد و جلوگیری از جمع کردن چهار کار مختلف در یک روش ایجاد کردیم. نیازی به دادن دسترسی کاربر به این روش ها نیست. اگر کاربر هنگام کار با یک برخورد دهنده به روش دسترسی داشته باشد convertBytesToSymbols()
، به احتمال زیاد متوجه نخواهد شد که این روش چیست و چرا به آن نیاز است. چه بایت هایی تبدیل می شوند؟ آنها از کجا آمده اند؟ چرا آنها را به متن تبدیل می کنیم؟ منطقی که در این روش اجرا می شود بخشی از رابط کاربری نیست. فقط متد readDataFromCollider()
بخشی از رابط است. با این چهار روش «داخلی» چه باید کرد؟ درست! دسترسی به آنها را با یک اصلاح کننده محدود کنید private
. به این ترتیب آنها به راحتی می توانند کار خود را در داخل کلاس انجام دهند و کاربر را که نیازی به منطق هر کدام جداگانه ندارد، سردرگم نکنند.
public class ColliderUtil {
public void readDataFromCollider(Path pathToData) {
byte[] colliderData = readByteData(pathToData);
String[] textData = convertBytesToSymbols(colliderData);
File fileWithData = saveToFile(textData);
printColliderData(fileWithData);
}
private byte[] readByteData(Path pathToData) {
// reads data in bytes
}
private String[] convertBytesToSymbols(byte[] colliderDataInBytes) {
// convert bytes to characters
}
private File saveToFile(String[] colliderData) {
// save the read data to a file
}
private void printColliderData(File fileWithColliderData) {
// print data from file
}
}
اصلاح کننده محافظت شده است
محدود کننده ترین اصلاح کننده دسترسی بعدی استprotected
. فیلدها و روش های تعیین شده با اصلاح کننده دسترسی protected
قابل مشاهده خواهند بود:
- در تمام کلاس هایی که در بسته بندی مشابه ما هستند.
- در تمام کلاس های جانشین کلاس ما.
protected
موارد بسیار کمتری از کاربرد وجود دارد private
، و آنها خاص هستند. تصور کنید که ما یک کلاس انتزاعی داریم AbstractSecretAgent
که نشان دهنده یک مامور مخفی برخی از آژانس های اطلاعاتی است، و همچنین بسته ای top_secret
که حاوی این طبقه و فرزندان آن است. طبقات بتنی - FBISecretAgent
، MI6SecretAgent
و MossadSecretAgent
غیره - از آن به ارث می رسد. در داخل کلاس abstract می خواهیم یک شمارنده عامل پیاده سازی کنیم. هنگامی که یک شی عامل جدید در جایی از برنامه ایجاد می شود، افزایش می یابد.
package top_secret;
public abstract class AbstractSecretAgent {
public static int agentCount = 0;
}
اما ماموران ما مخفی هستند! این بدان معنی است که فقط آنها و هیچ کس دیگری نباید از شماره آنها مطلع شوند. ما به راحتی میتوانیم یک اصلاحکننده protected
به فیلد اضافه کنیم agentCount
، و سپس یا اشیاء کلاسهای عامل مخفی دیگر، یا آن دستههایی که در بسته «مخفی» ما قرار دارند، میتوانند مقدار آن را دریافت کنند top_secret
.
public abstract class AbstractSecretAgent {
protected static int agentCount = 0;
}
برای چنین کارهای خاصی است که به یک اصلاح کننده نیاز است protected
:)
اصلاح کننده قابل مشاهده بسته
بعدی در لیست ما اصلاح کنندهdefault
یا، همانطور که به آن نیز گفته می شود، است package visible
. با یک کلمه کلیدی نشان داده نمی شود زیرا به طور پیش فرض در جاوا برای همه فیلدها و روش ها تنظیم شده است. اگر در کد خود بنویسید -
int x = 10;
... متغیر x
همین package visible
دسترسی را خواهد داشت. اگر یک متد (یا متغیر) با هیچ اصلاح کننده ای علامت گذاری نشده باشد، در نظر گرفته می شود که با "اصلاح پیش فرض" علامت گذاری شده است. متغیرها یا متدهایی با چنین اصلاحکنندهای (یعنی اصلاً بدون هیچ کدام) برای همه کلاسهای بستهای که در آن تعریف شدهاند قابل مشاهده هستند. و فقط به آنها. کاربردهای آن مانند اصلاح کننده محدود است protected
. اغلب، default
-access در بستهای استفاده میشود که در آن کلاسهای کاربردی وجود دارند که عملکرد همه کلاسهای دیگر این بسته را اجرا نمیکنند. بیایید یک مثال بزنیم. تصور کنید ما یک بسته " خدمات " داریم. در داخل آن کلاس های مختلفی وجود دارد که با پایگاه داده کار می کنند. به عنوان مثال، یک کلاس وجود دارد UserService
که داده های کاربر را از یک پایگاه داده می خواند، یک کلاس CarService
که داده های مربوط به اتومبیل ها را از همان پایگاه داده می خواند، و کلاس های دیگر، که هر کدام با نوع اشیاء خاص خود کار می کنند و داده های مربوط به آنها را از پایگاه داده می خوانند.
package services;
public class UserService {
}
package services;
public class CarService {
}
با این حال، زمانی که داده های پایگاه داده در یک فرمت هستند، اما ما در قالب دیگری به آن نیاز داریم، به راحتی می تواند اتفاق بیفتد. تصور کنید که تاریخ تولد کاربر در پایگاه داده با فرمت TIMESTAMP WITH TIME ZONE ذخیره می شود...
2014-04-04 20:32:59.390583+02
ما در عوض به ساده ترین شی نیاز داریم - java.util.Date
. برای این منظور میتوانیم services
یک کلاس ویژه در داخل بسته ایجاد کنیم Mapper
. او مسئول تبدیل داده ها از پایگاه داده به اشیاء جاوا خواهد بود که با آنها آشنا هستیم. یک کلاس کمکی ساده ما معمولاً همه کلاس ها را به صورت ایجاد می کنیم public class ClassName
، اما این ضروری نیست. ما می توانیم کلاس کمکی خود را به سادگی به صورت اعلام کنیم class Mapper
. در این مورد، هنوز هم کار خود را انجام می دهد، اما برای کسی خارج از بسته قابل مشاهده نیست services
!
package services;
class Mapper {
}
package services;
public class CarService {
Mapper mapper;
}
و این، در واقع، منطق درستی است: چرا فردی خارج از بسته، یک کلاس کمکی را می بیند که فقط با کلاس های همان بسته کار می کند؟
اصلاح کننده عمومی
و آخرین در لیست، اما نه کم اهمیت - اصلاح کنندهpublic
! شما در اولین روز تحصیل در JavaRush با او آشنا شدید public static void main(String[] args)
. اکنون که سخنرانیهای مربوط به رابطها را مطالعه کردهاید، هدف آن برای شما واضح است :) بالاخره public
برای ارائه چیزی به کاربران ایجاد شده است. به عنوان مثال، رابط برنامه شما. فرض کنید شما یک برنامه مترجم نوشته اید و می تواند متن روسی را به انگلیسی ترجمه کند. شما روشی ایجاد کرده اید translate(String textInRussian)
که در آن منطق لازم پیاده سازی می شود. شما این روش را با کلمه علامت گذاری کرده اید public
و اکنون بخشی از رابط کاربری خواهد بود:
public class Translator {
public String translate(String textInRussian) {
// translates text from Russian to English
}
}
می توانید یک تماس با این روش را با دکمه "ترجمه" در صفحه برنامه مرتبط کنید - و تمام! هر کسی می تواند از آن استفاده کند. بخش هایی از کد مشخص شده با اصلاح کننده public
برای کاربر نهایی در نظر گرفته شده است. برای مثالی از زندگی، private
اینها همه فرآیندهایی هستند که در هنگام کار تلویزیون در داخل تلویزیون رخ می دهند، و public
اینها دکمه های روی کنترل از راه دور تلویزیون هستند که کاربر می تواند آن را کنترل کند. در عین حال نیازی به دانستن نحوه عملکرد تلویزیون و نحوه عملکرد آن ندارد. کنترل از راه دور مجموعه ای public
از روش ها است: on()
, off()
, nextChannel()
, previousChannel()
, increaseVolume()
, decreaseVolume()
و غیره.
GO TO FULL VERSION