John Squirrels
مرحله
San Francisco

اصول OOP

در گروه منتشر شد
جاوا یک زبان شی گرا است. این بدان معنی است که شما باید برنامه های جاوا را با استفاده از یک پارادایم شی گرا بنویسید. و این پارادایم مستلزم استفاده از اشیاء و کلاس ها در برنامه های شما است. بیایید سعی کنیم از مثال‌هایی استفاده کنیم تا بفهمیم کلاس‌ها و اشیاء چیست و چگونه اصول اولیه OOP (انتزاع، وراثت، چندشکلی و کپسوله‌سازی) را در عمل اعمال کنیم.

شی چیست؟

دنیایی که ما در آن زندگی می کنیم از اشیا تشکیل شده است. با نگاهی به اطراف، می‌توانیم ببینیم که خانه‌ها، درختان، ماشین‌ها، مبلمان، ظرف‌ها و رایانه‌ها احاطه شده‌ایم. همه این چیزها اشیاء هستند و هر کدام دارای مجموعه ای از ویژگی ها، رفتارها و اهداف خاص هستند. ما به اشیا عادت داریم و همیشه از آنها برای اهداف بسیار خاص استفاده می کنیم. مثلاً اگر نیاز به سرکار داریم از ماشین استفاده می کنیم. اگر بخواهیم غذا بخوریم از ظروف استفاده می کنیم. و اگر بخواهیم استراحت کنیم، مبل راحتی پیدا می کنیم. انسان ها عادت دارند برای حل مشکلات زندگی روزمره به اشیا فکر کنند. این یکی از دلایل استفاده از اشیاء در برنامه نویسی است. به این روش برنامه نویسی شی گرا می گویند. بیایید یک مثال بزنیم. تصور کنید که یک گوشی جدید ساخته اید و می خواهید تولید انبوه را شروع کنید. به‌عنوان توسعه‌دهنده تلفن، می‌دانید که برای چیست، چگونه کار می‌کند و چه قسمت‌هایی دارد (بدنه، میکروفون، بلندگو، سیم‌ها، دکمه‌ها و غیره). علاوه بر این، فقط شما می دانید که چگونه این قطعات را به هم وصل کنید. اما شما قصد ندارید گوشی ها را شخصا بسازید - شما یک تیم کامل از کارگران برای انجام این کار دارید. برای اینکه نیازی به توضیح مکرر نحوه اتصال قطعات گوشی نباشید و اطمینان حاصل کنید که همه گوشی ها به یک شکل ساخته شده اند، قبل از شروع به تولید آنها، باید طرحی تهیه کنید که نحوه سازماندهی گوشی را توضیح دهد. در OOP، چنین توصیف، طراحی، نمودار یا الگو را یک کلاس می نامیم. هنگام اجرای برنامه اساس ایجاد اشیاء را تشکیل می دهد. یک کلاس توصیفی از اشیاء از نوع خاصی است - مانند یک الگوی معمولی متشکل از فیلدها، متدها و یک سازنده. یک شی نمونه ای از یک کلاس است. بر اساس توضیحات موجود در کلاس ایجاد می شود.

انتزاع - مفهوم - برداشت

بیایید اکنون به این فکر کنیم که چگونه می توانیم از یک شی در دنیای واقعی به یک شی در یک برنامه حرکت کنیم. ما از تلفن به عنوان مثال استفاده می کنیم. این وسیله ارتباطی سابقه ای بیش از 100 سال دارد. تلفن مدرن دستگاهی بسیار پیچیده تر از مدل قبلی خود در قرن نوزدهم است. هنگام استفاده از تلفن، به سازماندهی آن و فرآیندهای رخ داده در داخل آن فکر نمی کنیم. ما به سادگی از عملکردهای ارائه شده توسط توسعه دهندگان تلفن استفاده می کنیم: دکمه ها یا صفحه لمسی برای وارد کردن شماره تلفن و برقراری تماس. یکی از اولین رابط های تلفن یک میل لنگ بود که برای برقراری تماس باید چرخانده می شد. البته این خیلی راحت نبود. اما عملکرد خود را بدون نقص انجام داد. اگر مدرن‌ترین و اولین گوشی‌ها را مقایسه کنید، می‌توانید فوراً مهم‌ترین عملکردها را برای دستگاه اواخر قرن نوزدهم و برای تلفن هوشمند مدرن شناسایی کنید. آنها توانایی برقراری تماس و توانایی دریافت تماس هستند. در واقع این چیزی است که گوشی را به یک گوشی تبدیل می کند و نه چیز دیگری. اکنون فقط یک اصل OOP را اعمال کرده ایم: مهم ترین ویژگی ها و اطلاعات یک شی را شناسایی کنید. این اصل را انتزاع می نامند. در OOP، انتزاع همچنین می تواند به عنوان روشی برای نمایش عناصر یک کار دنیای واقعی به عنوان اشیا در یک برنامه تعریف شود. انتزاع همیشه با تعمیم ویژگی های خاص یک شی همراه است، بنابراین نکته اصلی جدا کردن اطلاعات معنی دار از ناچیز در زمینه کار در دست است. علاوه بر این، سطوح مختلف انتزاع می تواند وجود داشته باشد. بیایید سعی کنیم اصل انتزاع را در تلفن هایمان اعمال کنیم. برای شروع، ما رایج‌ترین انواع تلفن‌ها را شناسایی می‌کنیم - از اولین گوشی‌ها تا گوشی‌های امروزی. برای مثال، می‌توانیم آنها را به شکل نمودار در شکل 1 نشان دهیم. اصول OOP - 2با استفاده از انتزاع، اکنون می‌توانیم اطلاعات کلی در این سلسله مراتب شی را شناسایی کنیم: شی انتزاعی کلی (تلفن)، ویژگی‌های مشترک تلفن (به عنوان مثال سال ساخت آن). ایجاد)، و رابط مشترک (همه تلفن ها می توانند تماس بگیرند و تماس برقرار کنند). در جاوا چگونه به نظر می رسد:
public abstract class AbstractPhone {
    private int year;

    public AbstractPhone(int year) {
        this.year = year;
    }
    public abstract void call(int outgoingNumber);
    public abstract void ring(int incomingNumber);
}
در یک برنامه، می‌توانیم انواع جدیدی از گوشی‌ها را با استفاده از این کلاس انتزاعی و با استفاده از سایر اصول اولیه OOP ایجاد کنیم که در ادامه به بررسی آن‌ها می‌پردازیم.

کپسوله سازی

با انتزاع، آنچه را که برای همه اشیا مشترک است شناسایی می کنیم. اما هر نوع گوشی منحصر به فرد است و به نوعی با بقیه متفاوت است. در یک برنامه چگونه مرزها را ترسیم کنیم و این فردیت را شناسایی کنیم؟ چگونه آن را بسازیم تا کسی نتواند بطور تصادفی یا عمدی گوشی ما را بشکند یا سعی کند یک مدل را به مدل دیگر تبدیل کند؟ در دنیای واقعی، پاسخ واضح است: شما باید تمام قطعات را در یک قاب گوشی قرار دهید. به هر حال، اگر این کار را نکنید - در عوض تمام قسمت‌های داخلی تلفن و سیم‌های اتصال را در بیرون بگذارید - یک آزمایش‌گر کنجکاو قطعاً می‌خواهد تلفن ما را "بهبود" برساند. برای جلوگیری از چنین سرهم‌بندی، از اصل کپسوله‌سازی در طراحی و عملکرد یک شی استفاده می‌شود. این اصل بیان می کند که ویژگی ها و رفتار یک شی در یک کلاس واحد ترکیب می شوند، پیاده سازی داخلی شی از دید کاربر پنهان است و یک رابط عمومی برای کار با شی ارائه می شود. وظیفه برنامه نویس این است که تعیین کند کدام یک از ویژگی ها و روش های یک شی باید برای دسترسی عمومی در دسترس باشد، و کدام جزئیات پیاده سازی داخلی هستند که باید غیرقابل دسترسی باشند.

کپسوله سازی و کنترل دسترسی

فرض کنید اطلاعات مربوط به یک گوشی (سال تولید آن یا لوگوی سازنده) هنگام ساخت روی پشت آن حک شده باشد. اطلاعات (وضعیت آن) مختص این مدل خاص است. می‌توانیم بگوییم که سازنده مطمئن شده است که این اطلاعات تغییرناپذیر است - بعید است که کسی فکر کند حکاکی را حذف کند. در دنیای جاوا، یک کلاس وضعیت اشیاء آینده را با استفاده از فیلدها توصیف می کند و رفتار آنها با استفاده از روش ها توصیف می شود. دسترسی به وضعیت و رفتار یک شی با استفاده از اصلاح کننده های اعمال شده در فیلدها و روش ها کنترل می شود: خصوصی، محافظت شده، عمومی و پیش فرض. به عنوان مثال، ما تصمیم گرفتیم که سال تولید، نام سازنده و یکی از روش‌ها جزئیات پیاده‌سازی داخلی کلاس باشد و توسط سایر آبجکت‌های برنامه قابل تغییر نباشد. در کد، کلاس را می توان به صورت زیر توصیف کرد:
public class SomePhone {

    private int year;
    private String company;
    public SomePhone(int year, String company) {
        this.year = year;
        this.company = company;
    }
private void openConnection(){
    // findSwitch
    // openNewConnection...
}
public void call() {
    openConnection();
    System.out.println("Calling");
}

public void ring() {
    System.out.println("Ring-ring");
}

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

وراثت

بیایید نگاهی دیگر به نمودار گوشی ها بیندازیم. می بینید که این یک سلسله مراتب است که در آن یک مدل تمام ویژگی های مدل هایی که در امتداد شاخه خود قرار دارند را دارد و برخی از ویژگی های خود را اضافه می کند. به عنوان مثال، یک گوشی هوشمند از شبکه تلفن همراه برای ارتباط استفاده می کند (خواص تلفن همراه را دارد)، بی سیم و قابل حمل است (خواص تلفن بی سیم را دارد) و می تواند تماس بگیرد و تماس بگیرد (خواص تلفن را دارد). آنچه در اینجا داریم ارث بری خصوصیات شی است. در برنامه نویسی، وراثت به معنای استفاده از کلاس های موجود برای تعریف کلاس های جدید است. بیایید مثالی از استفاده از وراثت برای ایجاد کلاس تلفن هوشمند در نظر بگیریم. تمام تلفن های بی سیم از باتری های قابل شارژی تغذیه می شوند که عمر باتری مشخصی دارند. بر این اساس، این ویژگی را به کلاس تلفن های بی سیم اضافه می کنیم:
public abstract class CordlessPhone extends AbstractPhone {

    private int hour;

    public CordlessPhone (int year, int hour) {
        super(year);
        this.hour = hour;
    }
    }
تلفن‌های همراه ویژگی‌های یک تلفن بی‌سیم را به ارث می‌برند و روش‌های تماس و زنگ را در این کلاس پیاده‌سازی می‌کنیم:
public class CellPhone extends CordlessPhone {
    public CellPhone(int year, int hour) {
        super(year, hour);
    }

    @Override
    public void call(int outgoingNumber) {
        System.out.println("Calling " + outgoingNumber);
    }

    @Override
    public void ring(int incomingNumber) {
        System.out.println("Incoming call from " + incomingNumber);
    }
}
و در نهایت، ما کلاس گوشی های هوشمند را داریم که بر خلاف تلفن های همراه کلاسیک، سیستم عامل کاملی دارد. می توانید با افزودن برنامه های جدیدی که می توانند روی سیستم عامل آن اجرا شوند، عملکرد گوشی هوشمند خود را گسترش دهید. در کد، کلاس را می توان به صورت زیر توصیف کرد:
public class Smartphone extends CellPhone {

    private String operationSystem;

    public Smartphone(int year, int hour, String operationSystem) {
        super(year, hour);
        this.operationSystem = operationSystem;
    }
public void install(String program) {
    System.out.println("Installing " + program + " for " + operationSystem);
}

}
همانطور که می بینید، ما مقدار کمی کد جدید برای توصیف کلاس تلفن هوشمند ایجاد کردیم ، اما کلاس جدیدی با عملکرد جدید دریافت کردیم. این اصل OOP باعث می شود تا میزان کدهای جاوا به میزان قابل توجهی کاهش یابد و در نتیجه زندگی برنامه نویس آسان تر شود.

پلی مورفیسم

علیرغم تفاوت‌های ظاهری و طراحی انواع مختلف تلفن‌ها، می‌توانیم برخی از رفتارهای رایج را شناسایی کنیم: همه آن‌ها می‌توانند تماس بگیرند و تماس برقرار کنند و همه دارای مجموعه‌ای از کنترل‌های نسبتاً واضح و ساده هستند. از نظر برنامه نویسی، اصل انتزاع (که قبلاً با آن آشنا هستیم) به ما اجازه می دهد بگوییم که اشیاء تلفن دارای یک رابط مشترک هستند. به همین دلیل است که افراد می توانند به راحتی از مدل های مختلف گوشی هایی که دارای کنترل های یکسان هستند (دکمه های مکانیکی یا صفحه لمسی) استفاده کنند، بدون اینکه وارد جزئیات فنی دستگاه شوند. بنابراین، شما دائماً از تلفن همراه استفاده می کنید و می توانید به راحتی از تلفن ثابت دوست خود تماس بگیرید. اصل OOP که می گوید برنامه می تواند از اشیاء با یک رابط مشترک بدون هیچ گونه اطلاعاتی در مورد ساختار داخلی شی استفاده کند چند شکلی نامیده می شود. بیایید تصور کنیم که ما به برنامه خود برای توصیف کاربری نیاز داریم که می تواند از هر تلفنی برای تماس با کاربر دیگر استفاده کند. در اینجا نحوه انجام آن آمده است:
public class User {
    private String name;

    public User(String name) {
        this.name = name;
            }

    public void callAnotherUser(int number, AbstractPhone phone){
// And here's polymorphism: using the AbstractPhone type in the code!
        phone.call(number);
    }
}
 }
اکنون به شرح چند نوع گوشی می پردازیم. یکی از اولین گوشی ها:
public class ThomasEdisonPhone extends AbstractPhone {

public ThomasEdisonPhone(int year) {
    super(year);
}
    @Override
    public void call(int outgoingNumber) {
        System.out.println("Crank the handle");
        System.out.println("What number would you like to connect to?");
    }

    @Override
    public void ring(int incomingNumber) {
        System.out.println("The phone is ringing");
    }
}
یک تلفن ثابت معمولی:
public class Phone extends AbstractPhone {

    public Phone(int year) {
        super(year);
    }

    @Override
    public void call(int outgoingNumber) {
        System.out.println("Calling " + outgoingNumber);
    }

    @Override
    public void ring(int incomingNumber) {
        System.out.println("The phone is ringing");
    }
}
و در نهایت، یک تلفن ویدیویی جالب:
public class VideoPhone extends AbstractPhone {

    public VideoPhone(int year) {
        super(year);
    }
    @Override
    public void call(int outgoingNumber) {
        System.out.println("Connecting video call to " + outgoingNumber);
    }
    @Override
    public void ring(int incomingNumber) {
        System.out.println("Incoming video call from " + incomingNumber);
    }
  }
در متد main() اشیاء ایجاد می کنیم و متد callAnotherUser() را آزمایش می کنیم :
AbstractPhone firstPhone = new ThomasEdisonPhone(1879);
AbstractPhone phone = new Phone(1984);
AbstractPhone videoPhone=new VideoPhone(2018);
User user = new User("Jason");
user.callAnotherUser(224466, firstPhone);
// Crank the handle
// What number would you like to connect to?
user.callAnotherUser(224466, phone);
// Calling 224466
user.callAnotherUser(224466, videoPhone);
// Connecting video call to 224466
فراخوانی یک متد روی شی کاربر نتایج متفاوتی ایجاد می کند. یک پیاده سازی خاص از متد فراخوانی به صورت پویا در متد callAnotherUser() بر اساس نوع خاصی از شی ارسال شده در هنگام اجرای برنامه انتخاب می شود. این مزیت اصلی پلی مورفیسم است - توانایی انتخاب یک پیاده سازی در زمان اجرا. در مثال‌هایی از کلاس‌های تلفن ارائه شده در بالا، ما از روش overriding استفاده کردیم - ترفندی که در آن پیاده‌سازی متد تعریف‌شده در کلاس پایه را بدون تغییر امضای متد تغییر می‌دهیم. این اساساً جایگزین متد می شود: متد جدید تعریف شده در کلاس فرعی هنگام اجرای برنامه فراخوانی می شود. معمولاً وقتی روشی را لغو می کنیم، از حاشیه نویسی @Override استفاده می شود. به کامپایلر می گوید که امضای متدهای نادیده گرفته شده و نادیده گرفته شده را بررسی کند. در نهایت، برای اطمینان از سازگاری برنامه های جاوا با اصول OOP، نکات زیر را دنبال کنید:
  • شناسایی ویژگی های اصلی یک شی.
  • شناسایی ویژگی ها و رفتار مشترک و استفاده از وراثت هنگام ایجاد کلاس ها.
  • از انواع انتزاعی برای توصیف اشیا استفاده کنید.
  • سعی کنید همیشه متدها و فیلدهای مربوط به پیاده سازی داخلی کلاس را مخفی کنید.
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION