در این مقاله ابتدا با الگو های برنامه نویسی مختلف آشنا می شویم و پس از آن با روش برنامه نویسی object-oriented-programming (oop) آشنا شده و چهار اصل شی گرایی را به صورت کلی همراه با مثال بررسی میکنیم.
الگوی برنامه نویسی چیست ؟
در ساده ترین تعریف ممکن می توان گفت به مجموعه ای از استایل ها و شیوه های از برنامه نویسی گفته می شود که می توانیم به وسیله ی آن ها کد های خود را بسیار خوانا تر ، با پیچیدگی کمتر و خلاصه تر بنویسیم .
الگو های برنامه نویسی زیادی وجود دارد مانند Object-Oriented ،Functionalو Procedural
برای مثال زبان های برنامه نویسی مثل جاوااسکریپت و تایپ اسکریپت از الگوهای برنامه نویسی Object-Oriented ، Functional پشتیبانی می کنند.
برنامه نویسی شی گرا چیست؟
از محبوب ترین و معروف ترین الگو های برنامه نویسی برنامه نویسی شی گرا است ، در برنامه نویسی شی گرا همانطور که از اسم آن مشخص است کوچکترین عضو تشکیل دهنده ی برنامه ی ما را object ها (آبجکت) تشکیل میدهند ، به این معنا که با کنار هم قرار گرفتن تعدادی آبجکت برنامه ما ایجاد می شود.
برخی از زبان های برنامه نویسی که از برنامه نویسی شی گرا پشتیبانی می کنند عبارتند از :
C
Java
Ruby
Python
JavaScript
TypeScript
object چیست ؟
object واحدی است که شامل مجموعهای از متغیرها و توابع می شود این متغیرها و توابع درآبجکت ، پراپرتی ها و متدها نام دارند.
برای مثال obj زیر را در نظر بگیرید :
const person = {
firstName: "John",
lastName: "Doe",
id: 5566,
fullName: function() {
return this.firstName + " " + this.lastName;
}
};
در این مثال ابجکت person شامل پرارپتی های firstName ، lastName و id می شود و همچنین شامل متد fullName هست.
در واقع فانکشن های ما در ابجکت ها متد نام دارند.
چهار مفهوم اصلی در برنامه نویسی شی گرا :
کپسوله سازی (Encapsulation)
انتزاع (Abstraction)
ارث بری (Inheritance)
چند شکلی (Polymorphism)
Encapsulation (کپسوله سازی)
Encapsulation یا کپسوله سازی به این معناست که ما باید تمامی متغیر ها و متد های مربوط به هر بخش را به صورت جداگانه درون یک ابجکت بریزیم به شکلی که حالت کپسوله پیدا کرده و امکان دسترسی به این پراپرتی ها و متد ها از خارج این object به درون آن وجود نداشته باشد.
به مثال زیر توجه کنید :
let enterName = () => "enter name";
let enterFullname = () => "enter fullname";
در این مثال ابتدا دو function در حوزه ی سراسری تعریف کردیم که با توجه به سراسری بودن این فانکشن ها به راحتی می توان به آن ها دسترسی داشت ولی در مثال زیر ما دو متد را درون یک ابجکت قرار دادیم و با این کار امکان دسترسی را محدود کرده یا به عبارتی کپسوله سازی کرده ایم.
let Employee = {
enterName: () => 'enter name',
enterFullname: () => "enter fullname"
}
در کلاس ها به صورت زیر عمل میکنیم :
class Employee
{
constructor()
{
var name;
var rating;
}
getName()
{
return this.name;
}
setName(name)
{
this.name=name;
}
getRating()
{
return this.rating;
}
setRating(rating)
{
this.rating=rating;
}
}
var emp=new Employee();
emp.setName("Naren");
emp.setRating(9);
document.writeln(emp.getName()+" "+emp.getRating());
در مثال بالا ما با استفاده از کلمه کلیدی class ، کلاس Employee رو ایجاد کردیم و بعد از تعریف پراپرتی ها و متد های مورد نیاز تنها به ابجکت های امکان دسترسی به این کلاس را می دهیم که در واقع نمونه ای از همین کلاس باشند.
var emp=new Employee();
abstraction ( انتزاع )
اصل abstraction از تکرار کد جلوگیری می کند و قابلیت استفاده مجدد کد ها را افزایش می دهد ، با پنهان کردن جزئیات پیاده سازی و نمایش عملکرد کار را برای ما ساده می کند ، به بیان ساده تر می توان گفت با استفاده از این ویژگی ما فقط با مواردی سر و کار داریم که ضروری هستند مثلا در مثال قبل ما روند به نتیجه رسیدن متد setName را دنبال نمی کنیم و فقط نتیجه را برای ما به نمایش در می آورد ، با جلوگیری از تاثیر تغییرات یک متد بر روی سایر متد ها به وسیله ی پیاده سازی داخلی کلاس ها به کمک ما می آید.
چند نکته که باید به آن توجه کرد :
فقط کلاس های انتزاعی می توانند متدهای انتزاعی داشته باشند.
اگر کلاسی شامل متد انتزاعی باشد ، باید انتزاعی هم باشد.
به مثال زیر که مربوط به زبان برنامه نویسی تایپ اسکریپت می شود توجه کنید :
abstract class Person {
constructor(public name: string) { }
abstract sayHi(): void
}
class Man extends Person {
constructor(name: string) {
super(name)
this.name = name
}
sayHi() {
return `Hi, my name is ${this.name}.`
}
}
const joel = new Man('Joel')
joel.sayHi()
// Hi, my name is Joel.
در مثال بالا یک کلاس انتزاعی (abstract ) Person تعریف کردیم ، در داخل این کلاس ، متد انتزاعی () sayHi را تعریف کردیم و در مرحله بعد، کلاس فرزند جدید Man را ایجاد می کنیم و اجازه می دهیم از کلاس Person ارث بری کند و در داخل کلاس Man متد () sayHi را پیاده سازی می کنیم .
در جاوا اسکریپت پشتیبانی برای کلمه کلیدی abstract نداریم ولی میتوانیم مثال بالا را به زبان برنامه نویسی جاوا اسکریپت به شکل زیر نوشت :
class Person {
constructor(name) {
if (this.constructor === Person) {
throw new Error('Abstract classes can\'t be instantiated.')
}
}
sayHi() {
throw new Error('Method \'sayHi()\' must be implemented.')
}
}
class Man extends Person {
constructor(name) {
super(name)
this.name = name
}
sayHi() {
return `Hi, my name is ${this.name}.`
}
}
class Woman extends Person {
constructor(name) {
super(name)
this.name = name
}
}
const saed = new Man('Saed')
saed.sayHi()
const julii = new Woman('Julii')
julii.sayHi()
const tom = new Person('Tom')
Inheritance (ارث بری)
برای تعریف اصل Inheritance فرض کنید ما کلاسی ایجاد می کنیم که شامل تعدادی پراپرتی و متد است مانند مثال زیر در این مثال ما کلاس Car را داریم برای ساخت هر نوع ابجکت دیگری نیاز به تعریف مجدد این متد ها و پراپرتی های مشترک نیست و در واقع ما از کلاس Car ارث بری می کنیم.
let myCar = new Model("Ford", "Mustang");
class Car {
constructor(brand) {
this.carname = brand;
}
present() {
return 'I have a ' + this.carname;
}
}
class Model extends Car {
constructor(brand, mod) {
super(brand);
this.model = mod;
}
show() {
return this.present() + ', it is a ' + this.model;
}
}
let myCar = new Model("Ford", "Mustang");
مثالی دیگر از اصل Inheritance یا ارث بری
class Animal {
constructor(species, numOfLegs, sound) {
this.species = species
this.numOfLegs = numOfLegs
this.sound = sound
}
speak() {
return this.sound
}
}
class Dog extends Animal {
constructor(species, numOfLegs, sound, canRetrieve) {
super(species, numOfLegs, sound)
this.canRetrieve = canRetrieve
}
}
class Cat extends Animal {
constructor(species, numOfLegs, sound, canClimbTrees) {
super(species, numOfLegs, sound)
this.canClimbTrees = canClimbTrees
}
}
const charlie = new Dog('Dog', 4, 'Bark', true)
const kitty = new Cat('Cat', 4, 'Mew', true)
charlie.speak()
// Bark
charlie.canRetrieve
// true
charlie.canClimbTrees
// undefined
kitty.speak()
// Meow
kitty.canClimbTrees
// true
kitty.canRetrieve
// undefined
در مثال بالا یک کلاس والد با نام Animal داریم ، این کلاس شامل پراپرتی ها و متد های است که می تواند با کلاس های فرزند به اشتراک گذاشته شود ، در ادامه ما دو کلاس فرزند با نام های Cat و Dog داریم ، این کلاس ها می توانند با استفاده از کلمه کلیدی extends ، پراپرتی ها و متد های تعریف شده در کلاس پدر یعنی Animal را به ارث ببرند.
در کنار این ارث بری از کلاس والد میبینیم که هر کلاس هم میتواند متد ها و پراپرتی های خود را داشته باشد و سایر کلاس ها اجازه دسترسی به آن را نداشته باشند.
با استفاده از اصل Inheritance از نوشتن کد های تکراری جلوگیری می کنیم و کد های با قابلیت استفاده مجدد ایجاد می کنیم.
Polymorphism (چند شکلی)
اصطلاح Polymorphism از کلمه "Polymorph" گرفته شده است، که در آن "Poly" به معنای "زیاد" و "Morph" به معنای "تبدیل یک شکل به شکل دیگر" است ، در برنامه نویسی شی گرا، Polymorphism به ما این اجازه را می دهد که کار های مشابه را با روش های مختلف انجام دهیم.
این اصل به دو بخش Method overriding و Method overloading تقسیم می شود:
Method overriding
به مثال زیر توجه کنید :
class Animal {
speak() {
console.log("Animals have different sounds");
}
}
class Cat extends Animal {
speak() {
console.log("Cat says Meow Meow");
}
}
class Dog extends Animal {
speak() {
console.log("Dog say Woof Woof");
}
}
let x = [new Cat(), new Dog()]
x.forEach(function (info) {
info.speak();
});
در این مثال ما یک کلاس والد با نام Animal ایجاد کرده ایم که متد speak در آن وجود دارد ، با این وجود هنگام اجرای کد ها در خروجی متدی که درون کلاس های فرزند وجود دارد به نمایش در می آید و در واقع از متد والد خود چشم پوشی میکند
برای این نوع پیاده سازی ، متد جدید ما در کلاس فرزند باید دارای همان ویژگی های متد پدر باشد یعنی اگر متد پدر یک رشته را برمی گرداند ، متد فرزند هم باید یک رشته را برگرداند همچنین سطح دسترسی نباید محدودتر از سطح دسترسی متد پدر باشد یعنی برای مثال اگر متد کلاس والد به عنوان متدی عمومی اعلام شود متد overriding در کلاس فرزند هم باید عمومی باشد.
Method overloading (چند ریختی زمان کامپایل)
از این روش زمانی می توانیم استفاده کنیم که هر دو متد در کلاس پدر و فرزند دارای نام های یکسان ، ولی پارامترهای متفاوت باشند ، و به دو صورت می توان از آن استفاده کرد :
تعداد پارامترها تغییر کند یعنی پارامتر ها اضافه یا حذف شوند.
نوع پارامترها تغییر کند برای مثال کلاس فرزند ما پارامتری از نوع نامبر را به عنوان ورودی دریافت می کند ، سپس با استفاده از خاصیت overloading ما پارامتری از نوع رشته را به عنوان پارامتر دریافت می کنیم.
class Person {
sayNumber(num) {
return `The number is ${num}.`
}
}
class Boy extends Person {
sayNumber(numOne, numTwo) {
return `The number is ${numOne} and ${numTwo}.`
}
}
const jack = new Person()
jack.sayNumber(14)
// The number is 14.
const tony = new Boy()
tony.sayNumber(13, 17)
// The number is 13 and 17.
در واقع اصل Polymorphism باعث جلوگیری از نوشتن کد های تکراری می شود ، خوانایی کد را افزایش میدهد و پیچیدگی کد را کم میکند.
توسعه دهنده وب
شروع آشنایی من با دنیای برنامه نویسی 9 سال پیش بود ، اول مسیر با وردپرس آشنا شدم و بعد از اون شروع به یادگیری زبان جاوا اسکریپت کردم و رفته رفته سعی کردم یک برنامه نویس Front-end بشم که به مبحث گرافیک هم علاقه منده و هر روز تلاش میکنه تا پیشرفت کنه و اگر تجربه ای داره با بقیه به اشتراک بزاره.
- آموزش ساخت صفحه ی وب سایت با استفاده از HTML و css
- ساخت فروشگاه اینترنتی با html ، css و bootstrap - بخش اول
- آموزش نصب ، راه اندازی و کامپایل sass
- میانبر های مفید ادیتور VSCode
- سوالات مصاحبه ای از php و لاراول
این مقاله چقدر مفید بود ؟