
شی اشیاء جاوا و همچنین اشیاء دنیای واقعی دو ویژگی دارند: حالت و رفتار. به عنوان مثال، یک شی انسان دارای حالت (نام، جنسیت، خواب یا عدم...) و رفتار (مطالعه جاوا، راه رفتن، صحبت کردن...) است. هر شی جاوا حالت خود را در فیلدها ذخیره می کند و رفتار خود را از طریق متدها نشان می دهد. |
کپسوله سازی
کپسولهسازی دادهها به معنای پنهان کردن دادههای داخلی از دنیای بیرون و دسترسی به آنها تنها از طریق روشهایی است که در معرض عموم قرار گرفتهاند. معنی آن چیست؟ چه داده هایی؟ از چه کسی پنهان می شود؟ پنهان کردن به معنای محدود کردن دسترسی مستقیم به اعضای داده (فیلدهای) یک کلاس است.نحوه کار در جاوا:
- فیلدها خصوصی می شوند
- هر فیلد در یک کلاس دو متد خاص دریافت می کند: یک گیرنده و یک تنظیم کننده. متدهای دریافت کننده مقدار فیلد را برمی گرداند. متدهای Setter به شما امکان می دهند مقدار فیلد را به روشی غیرمستقیم اما مجاز تغییر دهید.
نمونه ای از کپسوله سازی در کد جاوا:
public class Student {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test{
public static void main(String[] args) {
Student firstStudent = new Student();
firstStudent.setName("John");
// The name field is private, so you can no longer do this: firstStudent.name = "John";
}
}
چرا باید از کپسولاسیون استفاده کنید؟
دلیل اصلی این است که تغییر کد خود را آسان تر کنید. تصور کنید که یک برنامه کاربردی برای یک مدرسه هاکی دارید و یک کلاس HockeyStudent با دو فیلد وجود دارد که نام و سن دانش آموز را هنگام ثبت نام در مدرسه ذخیره می کند. چیزی شبیه به این:public class HockeyStudent {
public String name;
public int ageOfEnrollment;
}
فیلد ageOfEnrollment عمومی است، بدون دریافتکننده یا تنظیمکننده... این کلاس توسط بسیاری از کلاسهای دیگر استفاده میشود، و همه چیز خوب بود تا اینکه برخی از توسعهدهندگان تصمیم گرفتند که یک فیلد int کافی نیست. برخی از بازیکنان هاکی در یک گروه تقریباً یک سال بزرگتر از همتایان خود هستند، بنابراین راحتتر است که آنها را به دو گروه تقسیم کنید، بسته به ماه تولدشان. بنابراین فیلد ageOfEnrollment باید به یک آرایه int (int[][]) تغییر کند : عدد اول برای سالهای کامل و دومی برای ماهها است. اکنون باید تمام کدهایی را که از کلاس Student استفاده می کنند، دوباره فاکتور کنید ! اما اگر فیلد ageOfEnrollment شما خصوصی است و دریافت کننده و تنظیم کننده دارید، همه چیز آسان تر است. اگر شرط تعیین سن دانش آموز تغییر کرد، فقط منطق متد setAgeOfEnrollment() را به روز کنید و کلاس های شما می توانند بدون هیچ مشکلی از Student استفاده کنند ! این مثال تا حدودی ساختگی است، اما امیدوارم توضیح دهد که چرا استفاده از کپسوله سازی ایده خوبی است.
وراثت
درک این اصل حتی بدون تجربه عملی آسانتر است. خودت را تکرار نکن (DRY) می تواند شعار مفهوم وراثت باشد. وراثت به شما امکان می دهد یک کلاس فرزند ایجاد کنید که فیلدها و متدهای کلاس والد را بدون تعریف مجدد آنها به ارث می برد. مطمئناً، میتوانید فیلدها و متدهای کلاس والد را در کلاس فرزند لغو کنید، اما این یک ضرورت نیست. علاوه بر این، می توانید حالت ها و رفتارهای جدیدی را در کلاس کودک اضافه کنید. کلاس های والد گاهی اوقات سوپرکلاس یا کلاس های پایه نامیده می شوند و کلاس های فرزند به عنوان زیر کلاس شناخته می شوند. کلمه کلیدی extensions جاوا برای پیاده سازی اصل وراثت در کد استفاده می شود.نحوه کار در جاوا:
- کلاس والد را ایجاد کنید.
- کلاس فرزند را با استفاده از کلمه کلیدی extends ایجاد کنید .
- در سازنده کلاس Child، از متد super(parentField1, parentField2, ...) برای تنظیم فیلدهای والد استفاده کنید.
سازنده یک روش خاص است که برای مقداردهی اولیه یک شی جدید ایجاد شده استفاده می شود. یک سازنده همان نام کلاس خود را دارد. دو نوع سازنده وجود دارد: پیش فرض (سازنده بدون آرگ) و سازنده پارامتری. یک کلاس باید حداقل یک سازنده داشته باشد (اگر سازنده های دیگر تعریف نشده باشند، سازنده پیش فرض را دارد) و می تواند تعداد زیادی از آنها را داشته باشد. هر بار که یک شی جدید ایجاد می کنید، سازنده آن را فرا می خوانید. در مثال بالا، این کار را در این خط انجام می دهید:
شما از کلمه کلیدی جدید برای فراخوانی سازنده پیش فرض کلاس Student استفاده می کنید : tudent() . |
برخی از قوانین:
- یک کلاس می تواند فقط یک والدین داشته باشد.
- یک کلاس والدین می تواند چندین کلاس فرزند داشته باشد.
- یک کلاس کودک می تواند کلاس های فرزند خود را داشته باشد.
نمونه ای از وراثت در کد جاوا
بیایید یک کلاس Phone ایجاد کنیم .public class Phone {
int price;
double weight;
// Constructor
public Phone(int price, double weight) {
this.price = price;
this.weight = weight;
}
void orderPhone(){
System.out.println("Ordering phone...");
}
}
البته، انواع مختلفی از تلفن ها وجود دارد، بنابراین بیایید دو کلاس کودک ایجاد کنیم: یکی برای گوشی های اندروید و دیگری برای آیفون. سپس چند فیلد و متدهایی را اضافه می کنیم که والد ندارد. و ما از super() برای فراخوانی سازنده ها برای مقداردهی اولیه فیلدهایی که کلاس والد دارد استفاده می کنیم.
نمونه ای از وراثت در جاوا
public class Android extends Phone {
// Some new fields
String androidVersion;
int screenSize;
String secretDeviceCode;
// Constructor
public Android(int price, double weight, String androidVersion, int screenSize, String secretDeviceCode) {
super(price, weight); // Android inherits Phone’s fields
//this - reference to the current object
//super - reference to the parent object
this.androidVersion = androidVersion;
this.screenSize = screenSize;
this.secretDeviceCode = secretDeviceCode;
}
// New Android-specific method, does not exist in the Phone class
void installNewAndroidVersion() {
System.out.println("installNewAndroidVersion invoked...");
}
}
public class IPhone extends Phone {
boolean fingerPrint;
public IPhone(int price, double weight, boolean fingerPrint) {
super(price, weight);
System.out.println("IPhone constructor was invoked...");
this.fingerPrint = fingerPrint;
}
void deleteIPhoneFromDb() {
System.out.println("deleteIPhoneFromDb invoked...");
}
@Override // This is about polymorphism, see below
void orderPhone(){
System.out.println("Ordering my new iPhone and deleting the old one...");
}
}
بنابراین، تکرار میکنیم: در جاوا، وراثت به شما امکان میدهد یک کلاس را با کلاسهای فرزند گسترش دهید که فیلدها و متدهای کلاس والد را به ارث میبرند. این یک راه عالی برای دستیابی به قابلیت استفاده مجدد کد است.
پلی مورفیسم
Polymorphism توانایی یک جسم برای شکل دادن است که به اشکال مختلف یا بهتر بگوییم به روش های مختلف عمل می کند. در جاوا، پلی مورفیسم معمولاً زمانی اتفاق میافتد که از یک مرجع کلاس والد برای ارجاع به یک شی کلاس فرزند استفاده شود.معنی آن چیست و چگونه در جاوا کار می کند:
پلی مورفیسم در جاوا چیست؟ به طور کلی، این بدان معناست که شما می توانید از یک نام روش برای اهداف مختلف استفاده کنید. دو نوع چندشکلی در جاوا وجود دارد: روش overriding (چند شکلی پویا) و روش overloading (چند شکلی استاتیک).غلبه بر روش
میتوانید متد کلاس والد را در کلاس فرزند لغو کنید و آن را مجبور کنید به روشهای متفاوتی کار کند. بیایید یک کلاس والد Musician با متد play() ایجاد کنیم .مثالی از چندشکلی در کد جاوا
public class Musician {
String name;
int age;
// Default constructor
public Musician() {
}
// Parameterized constructor
public Musician(String name, int age) {
this.name = name;
this.age = age;
}
void play() {
System.out.println("I am playing my instrument...");
}
}
نوازندگان مختلف از سازهای مختلف استفاده می کنند. بیایید دو کلاس کودک ایجاد کنیم: پیانیست و ویولن . به لطف چندشکلی، هر کدام نسخه مخصوص به خود را از متد play() اجرا می کنند . هنگام لغو، می توانید از حاشیه نویسی @Override استفاده کنید ، اما لازم نیست.
public class Pianist extends Musician {
String favoritePianoType;
public Pianist(String name, int age, String favoritePianoType) {
super(name, age);
this.favoritePianoType = favoritePianoType;
}
@Override
void play(){
System.out.println("I am playing the piano...");
}
}
نوازنده ویولن می تواند تکنواز یا عضو یک ارکستر باشد. بیایید وقتی متد play() خود را نادیده بگیریم، آن را در نظر بگیریم .
public class Violinist extends Musician {
boolean isSoloist;
public Violinist(String name, int age, boolean isSoloist) {
super(name, age);
this.isSoloist = isSoloist;
}
@Override
void play(){
if (isSoloist)
System.out.println("I am playing the violin solo...");
else
System.out.println("I am playing the violin in an orchestra...");
}
}
بیایید یک کلاس Demo ایجاد کنیم ، که در آن سه شیء، یک نمونه از هر یک از کلاس های ایجاد شده قبلی ایجاد می کنیم. ببینیم چه نتایجی می گیریم
public class Demo {
public static void main(String[] args) {
Musician musician = new Musician();
Violinist violinist = new Violinist("John", 32, true);
Pianist pianist = new Pianist("Glen", 30, "Acoustic");
System.out.println("Musician said:");
musician.play();
System.out.println("Violinist said:");
violinist.play();
System.out.println("Pianist said:");
pianist.play();
}
}
در اینجا چیزی است که ما دریافت می کنیم:
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo…
Pianist said:
I am playing the piano...
هر نوازنده ویولن و پیانیست یک نوازنده است، اما هر نوازنده ای ویولن یا پیانیست نیست. این بدان معناست که اگر نیازی به ایجاد روش جدید ندارید، می توانید از روش نوازندگی نوازنده استفاده کنید. یا می توانید با استفاده از کلمه کلیدی super ، روش والدین را از کودک فراخوانی کنید . بیایید این کار را در کد پیانیست انجام دهیم:
public class Pianist extends Musician {
String favoritePianoType;
@Override
void play(){
super.play();
System.out.println("I am playing the piano...");
}
}
حال بیایید متد main() خود را در کلاس Demo فراخوانی کنیم . نتیجه این است:
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...
اضافه بار روش
روش overloading به معنای استفاده از متدهای مختلف با نام مشابه در یک کلاس است. آنها باید از نظر تعداد، ترتیب یا نوع پارامترهایشان متفاوت باشند. فرض کنید که یک پیانیست می تواند پیانو آکوستیک و پیانو الکتریک بنوازد. برای نواختن برق، نوازنده به برق نیاز دارد. بیایید دو متد play() متفاوت ایجاد کنیم . اولی بدون پارامتر، برای پیانوی آکوستیک، و دومی با پارامتری که نشان می دهد برق در دسترس است یا خیر.public class Pianist extends Musician {
String name;
int age;
String favoritePianoType;
@Override
void play(){
super.play();
System.out.println("I am playing the piano...");
}
void play(boolean isElectricity){
if (isElectricity) {
System.out.println("The electricity is on.");
System.out.println("I am playing the piano...");
}
else System.out.println("I can't play this without electricity.");
}
}
به هر حال، شما می توانید از متد play() اول در متد دوم play(boolean) به این صورت استفاده کنید:
void play(boolean isElectricity){
if (isElectricity) {
System.out.println("The electricity is on.");
play();
}
else System.out.println("I can't play this without electricity.");
}
بیایید چند خط به کلاس Demo خود اضافه کنیم تا بارگذاری بیش از حد خود را نشان دهیم:
public class Demo {
public static void main(String[] args) {
Musician musician = new Musician();
Violinist violinist = new Violinist("John", 23, true);
Pianist pianist = new Pianist("Glen", 30, "Acoustic");
System.out.println("Musician said:");
musician.play();
System.out.println("Violinist said:");
violinist.play();
System.out.println("Pianist said:");
pianist.play();
System.out.println("The pianist will now try the electric piano:");
pianist.play(true);
System.out.println("The electricity has been shut off. Now when trying the electric piano, the pianist says:");
pianist.play(false);
}
}
در اینجا نتیجه است:
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...
The pianist will now try the electric piano:
The electricity is on.
I am playing my instrument...
I am playing the piano...
The electricity has been shut off. Now when trying the electric piano, the pianist says:
I can't play this without electricity.
جاوا می داند که بر اساس پارامترهای آن و نوع شی باید از کدام روش استفاده شود. این چند شکلی است.
انتزاع - مفهوم - برداشت
وقتی کلاسی را تعریف می کنیم، سعی می کنیم مدلی از چیزی بسازیم. برای مثال، فرض کنید در حال نوشتن یک بازی ویدیویی به نام MyRacer با ماشین های مسابقه ای مختلف هستیم. یک بازیکن می تواند یکی از آنها را انتخاب کند و بعداً آن را به روز کند یا یکی دیگر را خریداری کند. بنابراین… ماشین چیست؟ ماشین چیز بسیار پیچیدهای است، اما اگر میخواهیم یک بازی ویدئویی مسابقهای بسازیم (برخلاف یک شبیهساز رانندگی)، دیگر نیازی به توصیف هزاران دنده و واشر موجود در آن نیست. ما به مدل، حداکثر سرعت، ویژگیهای مانورپذیری، قیمت، رنگ آن نیاز داریم و شاید همین کافی باشد. این مدل ماشین بازی ماست. بعداً در MyRacer 2، فرض کنید تصمیم میگیریم تایرهایی اضافه کنیم که روی هندلینگ در جاده تأثیر میگذارند. در اینجا مدل متفاوت است، زیرا جزئیات بیشتری اضافه کردیم. بیایید انتزاع داده را به عنوان فرآیند شناسایی تنها ویژگی های مهم (یا ضروری) یک شی و نادیده گرفتن هرگونه جزئیات نامربوط تعریف کنیم. سطوح مختلف انتزاع وجود دارد. به عنوان مثال، اگر مسافر اتوبوس هستید، باید بدانید اتوبوس شما چگونه است و به کجا می رود، اما نیازی نیست که بدانید چگونه آن را رانندگی کنید. اگر راننده اتوبوس هستید، نیازی نیست بدانید که چگونه یک اتوبوس جدید بسازید - فقط باید بدانید که چگونه آن را رانندگی کنید. اما اگر سازنده اتوبوس هستید، باید به سطح پایین تری از انتزاع بروید، زیرا جزئیات طراحی اتوبوس برای شما بسیار مهم است. امیدوارم منظورم رو متوجه بشین.نحوه کار در جاوا:
بیایید چهار سطح انتزاعی را در جاوا، یا بهتر است بگوییم در OOP بسازیم - از پایین ترین (مشخص ترین) تا بالاترین (انتزاعی ترین).-
پایین ترین سطح انتزاع یک شی خاص است. موجودی با مجموعه ای از خصوصیات است که متعلق به یک کلاس خاص است. دارای مقادیر فیلد خاصی است
-
یک الگو برای ایجاد اشیا یک کلاس است. این توصیف مجموعه ای از اشیاء با خواص و ساختار داخلی مشابه است.
-
یک کلاس انتزاعی توصیفی انتزاعی از ویژگی های مجموعه ای از کلاس ها است (به عنوان یک الگو برای ارث بردن توسط کلاس های دیگر عمل می کند). سطح بالایی از انتزاع دارد، بنابراین ایجاد اشیاء مستقیماً از یک کلاس انتزاعی غیرممکن است. فقط کلاس های فرزند از کلاس های انتزاعی می توانند برای ایجاد اشیا استفاده شوند. یک کلاس انتزاعی ممکن است شامل متدهایی با پیاده سازی باشد، اما این یک الزام نیست.
-
اینترفیس ساختاری از ساختار زبان برنامه نویسی جاوا است که فقط شامل متدهای عمومی انتزاعی و فیلدهای ثابت استاتیک (استاتیک نهایی) است. به عبارت دیگر، نه کلاس های انتزاعی و نه رابط ها را نمی توان برای تولید اشیاء استفاده کرد.
نمونه ای از یک رابط در کد جاوا
interface Human {
public void struggle();
public void protect();
}
interface Vulcan {
int angleOfPointyEars;
public void turnOffEmotions(boolean isOn);
public void telepathy();
}
شما می توانید بیش از یک رابط را پیاده سازی کنید
The Spock class implements Human and Vulcan {
public void struggle() {
System.out.println("I am struggling...");
}
public void protect() {
System.out.println("You are under my protection!”);
}
public void turnOffEmotions(boolean isOn){
If (isOn) {
System.out.println("I am turning off my emotions.");
isOn= !isOn;
}
}
public void telepathy() {
System.out.println("Connecting to your brain...");
}
}
برای دانش آموزان مبتدی، که تمام مفاهیم اصلی برنامه نویسی شی گرا در جاوا را پوشش می دهد. علاوه بر 4 اصل اصلی OOP، جاوا همچنین دارای ارتباط، تجمیع و ترکیب است. می توانید آنها را "اصول OOP اضافی" بنامید. آنها شایسته مقاله جداگانه خود هستند.
GO TO FULL VERSION