شی‌گرایی در زبان برنامه‌نویسی جاوا به چه معنا است؟

زبان برنامه‌نویسی جاوا برای ساخت انواع مختلفی از برنامه‌های کاربردی تحت اندروید، وب و سازمانی استفاده می‌شود. یکی از مهم‌ترین و قدرتمندترین الگوهای برنامه‌نویسی که جاوا از آن پشتیبانی می‌کند، مفاهیم برنامه شی‌گرا است.

برنامه‌نویسی شی‌گرا مدلی است که انواع مختلفی از مفاهیم مانند وراثت، انتزاع، چندشکلی و غیره را ارائه می‌دهد و به برنامه‌نویسان کمک می‌کند کدهای ساخت‌یافته‌تر و دقیق‌تری بنویسند. هدف این مفاهیم پیاده‌سازی موجودیت‌های دنیای واقعی در برنامه‌های کاربردی است. در این‌جا، هدف تعریف متدها، توابع و متغیرهایی در قالب مفهومی به‌نام اشیا (Object) با قابلیت استفاده مجدد و حفظ امنیت برنامه کاربردی است. امروزه، پرکاربردترین و مهم‌ترین زبان‌های برنامه‌نویسی شی‌گرا مثل جاوا، سی پلاس پلاس، سی شارپ، جاوااسکریپت، پایتون و غیره از شی‌گرایی پشتیبانی می‌کنند.

پیشنهاد مقاله: آموزش سی شارپ یا آموزش جاوا؟ مقایسه کامل دو زبان برنامه نویسی

برنامه‌نویسی شی‌گرایی (Object-Oriented Programming) چیست؟

برنامه‌نویسی شی‌گرا راهکاری در اختیار برنامه‌نویسان قرار می‌دهد تا برنامه‌های کاربردی را بر مبنای کلاس‌ها و اشیاء پیاده‌سازی کنند. این الگوی برنامه‌نویسی نقش بسیار مهمی در زبان‌های پر کاربردی مثل جاوا دارد و گاهی اوقات از اصطلاح هسته جاوا (Core Of Java) برای توصیف نقش کلیدی که در این زبان دارد استفاده می‌شود.

برنامه‌نویسی شی‌گرا یک برنامه را در قالب اشیا و رابط‌های کاملاً تعریف شده سازمان‌دهی می‌کند تا کنترل داده‌ها به شکل دقیق‌تری انجام شود. در این مدل، برنامه‌نویسان نوع داده یک ساختار داده و عملیاتی که روی ساختار داده انجام می‌شود را تعریف می‌کنند. از مفاهیم مهم دنیای برنامه‌نویسی شی‌گرا باید به شی (Object)، کلاس (Class)، وراثت (Inheritance)، انتزاع (Abstraction)، پلی مورفیسم یا چندشکلی (Polymorphism) و کپسوله‌سازی (Encapsulation) اشاره کرد.

اشیا چیستند؟

اشیا همیشه به‌عنوان نمونه‌های یک کلاس خوانده می‌شوند. اشیاء در زبان جاوا از طریق کلاس‌ها ایجاد می‌شوند و رفتار و خصلت‌های کلاس‌ها را ارث‌بری می‌کنند. به‌طور مثال، رفتار اشیا توسط مجموعه‌ای از مقادیر و عملیات تعریف می‌شود.

هنگامی که اشیا تعریف می‌شوند، مقداری از فضای حافظه اصلی را اشغال می‌کنند، بنابراین باید در هنگام تعریف آن‌ها دقت کنید تا فضای حافظه اصلی بیهوده اشغال نشود. به‌طور مثال، فرض کنید، کلاسی به‌نام MyClass تعریف کرده‌ایم. اکنون فرآیند تعریف یک شی از این کلاس که Myobj نام دارد به شرح زیر انجام می‌شود:

Public class MyClass {

int x=10;

Public static void main (String args []) {

MyClass  Myobj= new MyClass ();

System.out.println(MyObj.x);

}

}

برای ساخت و تعریف این کلاس از کلیدواژه‌های Public و Class استفاده شده و در ادامه نام کلاس مشخص شده است. کلیدواژه Public نوع دسترسی اعضای کلاس را مشخص می‌کند. در این‌جا نوع دسترسی در کلاس MyClass عمومی است. اعضای عمومی برای تمام کلاس‌ها قابل مشاهده هستند. به‌عبارت دیگر، هر کلاس دیگری می‌تواند به یک فیلد یا متد عمومی دسترسی داشته باشد. در خط زیر، نحوه ساخت شی Myobj در کدهای فوق را مشاهده می‌کنید:

MyClass Myobj= new MyClass ();

برای آن‌که بتوانیم مقدار x  از شی ساخته شده را به‌دست آوریم از دستور زیر استفاده می‌کنیم:

System.out.println(Myobj.x);

امکان تعریف چند شی در یک کلاس واحد وجود دارد. توسعه‌دهندگان در زبان جاوا می‌توانند به یک شی که در یک کلاس تعریف شده در کلاس دیگر دسترسی داشته باشند. برای روشن شدن بحث اجازه دهید چند مثال در مورد نحوه ساخت چند شی در یک کلاس جاوا را بررسی کنیم. در مثال زیر نحوه ساخت چند شی در یک کلاس جاوا و دسترسی به اشیا از طریق کلاس‌های دیگر را بررسی می‌کنیم.

ابتدا کدهای زیر را در فایلی به‌نام MyClass.java ذخیره کنید.

Public class MyClass  {

int x=20;

int y=12;

}

کدهای زیر نیز در فایل Count.java نوشته شده‌اند:

Class Count {

Public static void main (String [] args)

{

MyClass myobj1 = new myobj1();

          MyClass myobj2 = new myobj2();

           System.out.println (myobj1.x);

System.out.println (myobj2.y);

}

}

در مثال فوق، اشیا myobj1‌ و myobj2 از کلاس عمومی Mybook در کلاس Count ساخته شده‌اند. هنگامی‌که کدهای مذکور اجرا می‌شوند، در خروجی اعداد 20 و 112 را چاپ می‌کنند.

کلاس در شی‌گرایی جاوا چه نقشی دارد؟

کلاس‌ها را می‌توان به‌عنوان سازنده‌هایی برای ساخت اشیا استفاده کرد. مجموعه اشیایی که خصوصیات و رفتار یکسان دارند کلاس نام دارند. کلاس‌ها کمیت‌هایی منطقی هستند که قالبی برای ساخت اشیا تعریف می‌کنند. کلاس‌ها می‌توانند اعضا مختلفی داشته باشند که از جمله می‌توان به فیلدها، متدها و سازنده‌ها اشاره کرد. در دنیای برنامه‌نویسی جاوا کلاس‌ها می‌توانند آغازکنندگان (Initializer) ایستا یا نمونه (Instance) باشند. هر شی ایجاد شده از یک کلاس، نمونه‌ای از آن کلاس نام دارد.

یک کلاس در شی‌گرایی جاوا چه مولفه‌هایی دارد؟

اعلان کلاس در جاوا (Class Declaration) به معنای تعریف و ساخت کلاس است که مولفه‌های زیر را دارد:

تعیین کننده سطح دسترسی (Access Modifiers): این مولفه در اعلان کلاس می‌تواند دسترسی عمومی یا پیش‌فرض داشته باشد.

بدنه کلاس: دستوراتی هستند که یک کلاس را تشکیل می‌دهند و میان دو علامت آکولاد { } قرار می‌گیرند.

ابر کلاس: کلاسی است که زیرکلاس‌های مختلفی دارد، اما یک زیرکلاس تنها می‌تواند یک والد داشته باشد.

نام کلاس: حرف اول نام کلاس در جاوا باید حرف بزرگ باشد.

واسط‌ها: یک کلاس می‌تواند بیش از یک واسط را پیاده‌سازی کند.

از کلمه کلیدی class برای ساخت یک کلاس در جاوا استفاده می‌شود. قطعه کد زیر تعریف یک کلاس در زبان جاوا را نشان می‌دهد:

class classname {

type instance variable 1;

type instance variable 2;

.

.

.

type instance variable n;

type methodname 1 (parameter list) {

// body od method

}

type methodname 2 (parameter list) {

// body od method

}

type methodnamen (parameter list) {

// body od method

}

 }

همان‌گونه که اشاره شد، یک کلاس می‌تواند دارای متغیرها، داده‌ها و متدهایی باشد. به متغیرها و داده‌های تعریف شده در یک کلاس، متغیرهای نمونه گفته می‌شود. همچنین، متدها و متغیرهایی که در یک کلاس تعریف شده‌اند، اعضای آن کلاس هستند.

انتزاع (Abstraction) چیست؟

یکی از مفاهیم مهم دنیای شی‌گرایی، انتزاع است که اهمیت زیادی دارد. در ساده‌ترین تعریف، انتزاع به معنای پنهان کردن جزییات غیر ضروری از دید کاربر است، به‌طوری که تنها به آن چیزی که برای انجام کار به آن نیاز دارد دسترسی داشته باشد. به بیان دیگر، انتزاع سعی می‌کند تنها اطلاعات مورد نیاز را نمایش دهد. در دنیای برنامه‌نویسی، انتزاع به معنای انتخاب داده‌های مناسب از میان حجم زیادی از داده‌ها، با هدف نمایش اطلاعات مورد نیاز و کاهش پیچیدگی طراحی برنامه‌های کاربردی است. در جاوا امکان انتزاعی کردن کلاس‌ها و متدها وجود دارد. در این‌جا، کلاس انتزاعی، نوعی کلاس است که چند متد انتزاعی در آن تعریف شده‌اند. در این‌جا مفهوم دیگری به‌نام متد انتزاعی وجود دارد که تنها تعریف متدها را دارد و هیچ‌گونه پیاده‌سازی را شامل نمی‌شود.

هنگامی‌که یک شی با روش انتزاع داده‌ای تعریف می‌شود، امکان استفاده از مجموعه‌های یکسانی از داده‌ها را برای کاربردهای مختلف به‌وجود می‌آورد. پرسشی که مطرح می‌شود این است که چه زمانی باید از متدهای انتزاعی استفاده کرد؟ هنگامی که بیش از یک زیرکلاس کار یکسانی را به روش‌های مختلف و از طریق پیاده‌سازی‌های مختلف انجام می‌دهند. یک کلاس انتزاعی می‌تواند متدهای انتزاعی و متدهای معمولی را داشته باشد.

برای درک بهتر موضوع به مثال زیر دقت کنید. در مثال فوق، هدف ساخت یک درخواست‏نامه دانش‌آموزی برای دریافت اطلاعات از دانش‌آموزان است. اطلاعاتی که باید جمع‌آوری شوند، نام، کلاس، نشانی، تاریخ تولد، نام پدر، نام مادر و سایر موارد هستند. در این‌جا، ممکن است همه اطلاعات جمع‌آوری شده برای پر کردن درخواست‌نامه احتیاج نباشند. از این‌رو، تنها اطلاعاتی گزینش می‌شوند که برای کامل کردن درخواست‌نامه ضروری هستند. برای انجام این‌کار، اطلاعات درست انتخاب شوند. این فرآیند در دنیای شی‌گرایی انتزاع نام دارد. در ادامه مثالی از یک کلاس انتزاعی را مشاهده می‌کنید.

//abstract parent class

        Abstract class Language {

         //abstract method

      public abstract void sound ( ) ;

         }

     Public class lion extends language {

      Public void sound ( ) {

System.out.println (“ Hello “ );

}

public Static void main ( String args [ ] ) {

 language obj = new word ( );

obj. sound ();

}

}

خروجی قطعه کد فوق واژه Hello است. در دستورات بالا، یک کلاس والد به‌نام Language تعریف می‌شود که یک متد انتزاعی عمومی به‌نام sound دارد. در ادامه، یک کلاس عمومی در کلاس Language به‌نام word تعریف شده که آن‌را بسط می‌دهد و زیر کلاس آن به‌شمار می‌رود. متد sound برای کلاس word به گونه‌ای تعریف شده که کلمه Hello در خروجی نشان داده می‌شود. در تابع اصلی برنامه، یک شی از کلاس word با نام obj ساخته شده که با فراخوانی متد sound‌ روی این شی، واژه Hello را چاپ می‌کند.

وراثت در دنیای جاوا

وراثت رویکردی است که با استفاده از آن یک شی خصلت‌های شی دیگری را ارث‌بری می‌کند. وراثت از طبقه‌بندی سلسله مراتبی (Hierarchical Classification) پشتیبانی می‌کند، به این صورت است که کلاس‌های جدیدی بر مبنای بر کلاس‌های فعلی ساخته می‌شوند. هنگامی‌که کلاس جدیدی از کلاس فعلی ارث‌بری می‌کند، می‌توان از متدها و فیلدهای کلاس والد استفاده مجدد کرد. در ساده‌ترین تعریف، وراثت رابطه والد و فرزند است. در پارادایم شی‌گرایی پنج نوع وراثت به‌نام‌های منفرد (Single Level)، چند سطحی (Multilevel)، چندتایی (Multiple)، ترکیبی (Hybrid) و سلسله مراتبی (Hierarchical Level) وجود دارد.

وراثت منفرد

یک کلاس مشتق شده خصوصیات وراثتی را از یک کلاس والد ارث‌ می‌برد. در روش مذکور امکان استفاده مجدد از کدها و افزودن ویژگی‌های جدید به کدها وجود دارد. در قطعه کد زیر، کلاس b ویژگی‌هایش را از کلاس a ارث‌ می‌برد. a کلاس والد است و b کلاس مشتق شده است.

Class a {

}

Class b extends class a {

}

وراثت چند سطحی

یک کلاس از کلاس دیگری ارث می‌برد، در حالی که کلاس دیگری قادر به ارث‌بری از کلاس دیگر است. در این حالت، کلاس‌ها بیش از یک کلاس والد دارد. ترکیب نحوی وراثت چندسطحی در جاوا در قطعه کد زیر نشان داده شده است:

Class a {

….

}

Class b extends class a {

….

}

Class c extends class b {

}

وراثت سلسله مراتبی

یک کلاس والد چند کلاس مشتق شده (زیر کلاس) دارد. به‌عبارت دیگر چند کلاس فرزند یک کلاس والد دارند. در قطعه کد زیر ترکیب نحوی وراثت سلسله مراتبی را مشاهده می‌کنید:

Class a {

}  

Class b extends class a {

..

}

Class c extends class a {

..

}

وراثت ترکیبی

تلفیقی از وراثت چندتایی و وراثت چند سطحی است. البته دقت کنید در جاوا وراثت چندتایی به‌شکل مستقیم پشتیبانی نمی‌شود، زیرا برای جاوا ابهام ایجاد می‌کند. فلذا این نوع وراثت تنها از طریق واسط‌ها قابل اجر است. به‌طور مثال، کلاس a، کلاس والد برای کلاس b و c است و کلاس b و c، کلاس والد برای کلاس d هستند. کلاس b و c، کلاس‌های مشتق شده یا فرزند کلاس a هستند و کلاس d، کلاس فرزند یا مشتق شده برای کلاس‌های b و c است. در قطعه کد زیر ابرکلاس Add و زیرکلاس Sub تعریف شده و از کلمه کلیدی extend برای ساخت زیرکلاس ‌Sub استفاده شده است. با اجرای قطعه کد زیر، عبارت total = 22 در خروجی نشان داده می‌شود.

// a simple example of inheritance

//create a superclass

Class Add {

int my;

int by;

void setmyby (int xy, int hy) {

my=xy;

by=hy;

}

}

/create a sub class

class b extends add {

int total;

void sum () {

public Static void main (String args [ ] ) {

b subOb= new b ( );

subOb. Setmyby (10, 12);

subOb. Sum ( ) ;

System.out.println(“total =” + subOb. Total);

}

}

چند ریختی در جاوا

پلی‌مورفیسم که چند ریختی ترجمه می‌شود به برنامه‌نویسان اجازه می‌دهد یک کار واحد را به روش‌های مختلف انجام دهند. پلی‌مورفیسم در زبان برنامه‌نویسی جاوا برای خوانایی و استفاده مجدد از داده‌ها استفاده می‌شود. در مبحث چند ریختی کلاس‌های زیادی به‌واسطه ارث‌بری با یکدیگر مرتبط هستند. چند ریختی به دو نوع اصلی چند ریختی ایستا (Static Polymorphism) که برخی منابع از اصطلاح چند ریختی زمان کامپایل (Compile Time Polymorphism) برای توصیف آن استفاده می‌کنند و چند ریختی پویا (Dynamic Polymorphism) که برخی منابع از اصطلاح چند ریختی زمان اجرا (Runtime Polymorphism) برای توصیف آن استفاده می‌کنند، تقسیم می‌شوند. برنامه‌نویسان برای پیاده‌سازی پلی‌مورفیسم به دو شیوه اضافه بار (Overloading) یا رونویسی کردن (Overriding) استفاده می‌کنند.

مدل رونویسی، همیشه از طریق متغیر مرجع فراخوانی می شود. با استفاده از روش overloading و روش overriding می‌توانیم چندشکلی را پیاده‌سازی کنیم دهیم. به‌طور کلی، مفهوم چندشکلی اغلب به‌عنوان یک رابط، بیان می‌شود. در چند ریختی پویا، فراخوانی یک متد، رونویسی می‌شود و به جای زمان کامپایل در زمان اجرا انجام می‌شود. در پلی‌مورفیسم زمان اجرا، فراخوانی روش همیشه از طریق متغیر مرجع (Reference Variable) انجام می‌شود. در بیشتر موارد، پلی‌مورفیسم به‌عنوان یک واسط، با چند متد انجام می‌شود. در پلی‌مورفیسم هدف این است که از یک واسط به‌عنوان کلاس کلی عملکرد با هدف کاهش پیچیدگی‌ها استفاده کرد. برای درک بهتر موضوع به مثال زیر دقت کنید:

public class Bird {

Public void sound ( ) {

System.out.println ( “ birds sounds “ );

}

}

public class pigeon extends Bird {

@override

public void sound ( ) {

System.out.println( “ cooing ” ) ;

}

}

public class sparrow extends Bird ( ) {

….

@override

Public void sound ( ){

System.out.println( “ chip ” ) ;

}

}

در قطعه کد بالا، عملکرد متد sound() در هر کلاس متفاوت از دیگری است و هر مرتبه فراخوانی می‌شود خروجی مختلفی را نشان می‌دهد.

در پلی مورفیسم زمان کامپایل که برخی منابع از اصطلاح پلی‌مورفیسم ایستا برای توصیف آن استفاده می‌کنند از طریق سربارگذاری متد (Method Overloading) یا مقیدسازی پویا (Dynamic Binding) انجام می‌شود. این نوع پلی‌مورفیسم برای فراخوانی یک متد رونویسی‌شده (overridden) استفاده می‌شود. در فرآیند فوق به جای زمان کامپایل از رویکرد پویا استفاده می‌شود.

چگونه کپسوله‌سازی در جاوا پیاده‌سازی می‌شود؟

کپسوله‌سازی یکی دیگر از مباحث مهم برنامه‌نویسی شی‌گرایی است. کپسوله‌سازی از طریق مرتبط کردن داده‌ها و کدها به یکدیگر و پیاده‌سازی یک واحد منفرد انجام می‌شود. کپسوله‌سازی کمک می‌کند تا امنیت کدها بیشتر شده و دستکاری‌های غیرمجاز در کدها کمتر شود. در روش فوق، متدهای موجود در هر کلاس تنها به داده‌های همان کلاس دسترسی دارند و متدهای کلاس‌های دیگر به داده‌های کلاس مورد نظر دسترسی نخواهند داشت. بزرگ‌ترین مزیتی که رویکرد کپسوله‌سازی ارائه می‌کند مخفی کردن داده‌ها است. به‌طوری که داده‌های کلاس کپسوله شده از دسترس دیگر کلاس‌ها مخفی می‌شوند و آن‌ها به داده‌های فوق دسترسی نخواهند داشت.

کپسوله‌سازی در جاوا در قالب یک مکانیزم پوشش محافظ (Protective Wrapper) رفتار می‌کند تا برنامه‌نویسان دیگر به روش‌های مختلف موفق نشوند به کدها و داده‌ها دسترسی داشته باشند. در روش فوق یک واسط تعریف می‌شود. کپسوله‌سازی با استفاده از اعلان متغیرها به شکل خصوصی و ساخت متدهای تنظیم‌کننده (Setter) و گیرنده (Getter) به منظور تغییر و نشان دادن مقدار متغیرها پیاده‌سازی می‌شود. در این روش، فیلد کلاس‌ها فقط خواندنی (Read Only) و فقط نوشتنی (Write Only) تعیین می‌شوند. کپسوله‌سازی قابلیت استفاده مجدد از داده‌ها را بیشتر می‌کند و استفاده از کدهای آن، جهت برخی فرآیندهای مهندسی مثل تست واحد (Unit Testing) را ساده‌تر می‌کند. برای درک مفهوم کپسوله‌سازی به قطعه کد زیر دقت کنید:

class animal {

// private field

private int age;

//getter method

Public int getage ( ) {

return age;

}

//setter method

public void setAge ( int age ) {

this. Age = age;

}

}

class Main {

public static void main (String args []);

//create an object of person

Animal a1= new Animal ();

//change age using setter

A1. setAge (12);

// access age using getter

System.out.println(“ animal age is ” + a1. getage ( ) );

}

}

قطعه کد فوق عبارت Animal age is 12 را چاپ می‌کند. در مثال بالا، فیلد خصوصی به‌نام age تعریف کردیم که دسترسی به آن تنها در این کلاس وجود دارد. برای دسترسی به age از متدهای عمومی تنظیم‌کننده و گیرنده استفاده می‌شود. خصوصی‌سازی age دسترسی‌های غیر مجاز بیرون از کلاس را محدود می‌کند. از این‌رو، به روش فوق پنهان‌سازی داده‌ها نیز گفته می‌شود.

کلام آخر

در این مقاله سعی کردیم، مهم‌ترین مفاهیم دنیای برنامه‌نویسی شی‌گرایی در جاوا را بررسی کنیم. همان‌گونه که مشاهده کردید، شی‌گرایی در زبان‌های برنامه‌نویسی، کدنویسی را ساده‌تر، ساخت‌یافته‌تر، ایمن‌تر و خوانا‌تر می‌کند. به‌طوری که اگر تصمیم گرفتید تغییراتی در کدها اعمال کنید، نیازی نیست از ابتدا همه چیز را تغییر دهید. در انتها باید به این نکته اشاره کنیم که شی‌گرایی در جاوا مباحث دیگری مثل، وابستگی‌ها (Coupling)، پیوستگی (Cohesion)، انجمن‌پذیری (Association) و غیره را شامل می‌شود. با این‌حال، مفاهیمی که اشاره شدند از مهم‌ترین مباحث دنیای شی‌گرایی هستند.

منبع:

https://www.mygreatlearning.com/blog/oops-concepts-in-java/

ثبت ديدگاه