CodeGym /Java блог /Случаен /Принципи на ООП
John Squirrels
Ниво
San Francisco

Принципи на ООП

Публикувано в групата
Java е обектно-ориентиран език. Това означава, че трябва да пишете Java програми, използвайки обектно-ориентирана парадигма. И тази парадигма включва използването на обекти и класове във вашите програми. Нека се опитаме да използваме примери, за да разберем Howво представляват класовете и обектите и How да приложим основните принципи на ООП (абстракция, наследяване, полиморфизъм и капсулиране) на практика.

Какво е обект?

Светът, в който живеем, е съставен от предмети. Оглеждайки се наоколо, виждаме, че сме заобиколени от къщи, дървета, коли, мебели, чинии и компютри. Всички тези неща са обекти и всяко от тях има набор от специфични характеристики, поведение и цели. Ние сме свикнали с предмети и винаги ги използваме за много специфични цели. Например, ако трябва да стигнем до работа, използваме кола. Ако искаме да ядем, използваме съдове. А ако искаме да си починем, намираме удобен диван. Хората са свикнали да мислят от гледна точка на обекти, за да решават проблеми в ежедневието. Това е една от причините, поради които обектите се използват в програмирането. Този подход се нарича обектно-ориентирано програмиране. Да дадем пример. Представете си, че сте разработor нов телефон и искате да започнете масово производство. Като разработчик на телефона вие знаете за Howво служи, How функционира и Howви са неговите части (корпус, микрофон, високоговорител, кабели, бутони и др.). Нещо повече, само вие знаете How да свържете тези части. Но вие не планирате да правите телефоните лично - имате цял екип от работници, които да направят това. За да премахнете необходимостта да обяснявате многократно How да свързвате частите на телефона и за да сте сигурни, че всички телефони са напequalsи по един и същи начин, преди да започнете да ги произвеждате, трябва да направите чертеж, който описва How е организиран телефонът. В ООП ние наричаме такова описание, чертеж, диаграма or шаблон клас. Той формира основата за създаване на обекти, когато програмата работи. Класът е описание на обекти от определен тип — като общ шаблон, състоящ се от полета, методи и конструктор. Обектът е екземпляр на клас.

Абстракция

Нека сега помислим How можем да преминем от обект в реалния свят към обект в програма. Ще използваме телефона като пример. Това средство за комуникация има история, която обхваща повече от 100 години. Съвременният телефон е много по-сложно устройство от своя предшественик от 19-ти век. Когато използваме телефона, ние не мислим за неговата организация и процесите, протичащи в него. Ние просто използваме функциите, предоставени от разработчиците на телефона: бутони or сензорен екран за въвеждане на телефонен номер и провеждане на повиквания. Един от първите телефонни интерфейси беше манивела, която трябваше да се завърти, за да се осъществи повикване. Разбира се, това не беше много удобно. Но изпълни функцията си безупречно. Ако сравните най-модерните и първите телефони, можете веднага да идентифицирате най-важните функции за устройството от края на 19-ти век и за съвременния смартфон. Те са възможността за осъществяване на повиквания и възможността за получаване на повиквания. Всъщност това прави телефона телефон, а не нещо друго. Сега току-що приложен принцип на ООП: идентифицирайте най-важните характеристики и информация на обекта. Този принцип се нарича абстракция. В ООП абстракцията може също да се дефинира като метод за представяне на елементи от задача от реалния свят като обекти в програма. Абстракцията винаги е свързана с обобщаването на определени свойства на даден обект, така че основното е да се отдели смислената информация от незначителната в контекста на поставената задача. Освен това може да има няколко нива на абстракция. Позволявам' Опитваме се да приложим принципа на абстракцията към нашите телефони. Като начало ще идентифицираме най-често срещаните типове телефони — от първите телефони до тези от наши дни. Например, можем да ги представим под формата на диаграмата на фигура 1. Принципи на ООП – 2Използвайки абстракция, сега можем да идентифицираме общата информация в тази йерархия на обекти: общият абстрактен обект (телефон), общите характеристики на телефона (напр. годината на създаването му) и общият интерфейс (всички телефони могат да приемат и осъществяват повиквания). Ето How изглежда в Java:

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);
}
В една програма можем да създаваме нови типове телефони, използвайки този абстрактен клас и прилагайки други основни принципи на ООП, които ще разгледаме по-долу.

Капсулиране

С абстракцията ние идентифицираме Howво е общо за всички обекти. Но всеки вид телефон е уникален, по няHowъв начин се различава от другите. Как в една програма очертаваме граници и идентифицираме тази индивидуалност? Как да направим така, че никой да не може случайно or умишлено да счупи телефона ни or да се опита да преобразува един модел в друг? В реалния свят отговорът е очевиден: трябва да поставите всички части в калъф за телефон. В края на краищата, ако не го направите — instead of това оставите всички вътрешни части на телефона и свързващите кабели отвън — някой любопитен експериментатор определено ще иска да „подобри“ нашия телефон. За да се предотврати подобно бърникане, принципът на капсулиране се използва при проектирането и работата на обекта. Този принцип гласи, че атрибутите и поведението на обекта се комбинират в един клас, обектът Вътрешната реализация е скрита от потребителя и е осигурен публичен интерфейс за работа с обекта. Задачата на програмиста е да определи кои от атрибутите и методите на даден обект трябва да бъдат достъпни за публичен достъп и кои са вътрешни детайли за изпълнение, които трябва да бъдат недостъпни.

Капсулация и контрол на достъпа

Да предположим, че информация за телефона (годината му на производство or логото на производителя) е гравирана на гърба му, когато е произведен. Информацията (нейното състояние) е специфична за този конкретен модел. Можем да кажем, че производителят се е погрижил тази информация да е неизменна - малко вероятно е някой да се сети да премахне гравирането. В света на Java класът описва състоянието на бъдещи обекти с помощта на полета, а поведението им се описва с помощта на методи. Достъпът до състоянието и поведението на обект се контролира с помощта на модификатори, приложени към полета и методи: частни, защитени, публични и по подразбиране. Например решихме, че годината на производство, името на производителя и един от методите са вътрешни детайли за изпълнение на класа и не могат да бъдат променяни от други обекти в програмата. В codeа,

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 също така ни оставя възможността свободно да променяме вътрешната реализация на метода, тъй като методът гарантирано няма да бъде използван от or да прекъсва работата на други обекти. За да работим с нашия обект, оставяме методите за повикване и звънене достъпни с помощта на модификатора public. Предоставянето на публични методи за работа с обекти също е част от капсулирането, тъй като ако достъпът бъде отказан напълно, той ще стане безполезен.

Наследство

Нека да погледнем отново диаграмата на телефоните. Можете да видите, че това е йерархия, в която моделът има всички характеристики на моделите, разположени по-високо по неговия клон, и добавя някои свои собствени. Например, смартфонът използва клетъчна мрежа за комуникация (има свойствата на мобилен телефон), безжичен е и преносим (има свойствата на безжичен телефон) и може да получава и осъществява повиквания (има свойствата на телефон). Това, което имаме тук, е наследяване на свойствата на обекта. В програмирането наследяването означава да се използват съществуващи класове за дефиниране на нови. Нека разгледаме пример за използване на наследяване за създаване на клас смартфон. Всички безжични телефони се захранват от акумулаторни батерии, които имат определен живот на батерията. Съответно добавяме това свойство към класа безжични телефони:

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);
    }
}
И накрая, имаме класа смартфони, който за разлика от класическите мобилни телефони разполага с пълноценна операционна система. Можете да разширите функционалността на вашия смартфон, като добавите нови програми, които могат да работят на неговата операционна система. В codeа класът може да бъде описан по следния начин:

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);
}

}
Както можете да видите, създадохме доста нов code, за да опишем класа Smartphone , но получихме нов клас с нова функционалност. Този принцип на ООП прави възможно значително намаляване на необходимия Java code, като по този начин улеснява живота на програмиста.

Полиморфизъм

Въпреки разликите във външния вид и дизайна на различните видове телефони, можем да идентифицираме някои общи поведения: всички те могат да получават и извършват повиквания и всички имат доста ясен и прост набор от контроли. По отношение на програмирането, принципът на абстракцията (с който вече сме запознати) ни позволява да кажем, че телефонните обекти имат общ интерфейс. Ето защо хората могат лесно да използват различни модели телефони, които имат едни и същи контроли (механични бутони or тъчскрийн), без да се задълбочават в техническите детайли на устройството. По този начин вие използвате постоянно мобилен телефон и лесно можете да се обадите от стационарния телефон на ваш приятел. Принципът на ООП, който казва, че програмата може да използва обекти с общ интерфейс без ниHowва информация за вътрешната структура на обекта, се нарича полиморфизъм. Позволявам' Представете си, че имаме нужда от нашата програма, за да опишем потребител, който може да използва всеки телефон, за да се обади на друг потребител. Ето How можем да го направим:

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() въз основа на конкретния тип обект, предаден, когато програмата работи. Това е основното предимство на полиморфизма – възможността за избор на имплементация по време на изпълнение. В примерите за телефонни класове, дадени по-горе, използвахме отмяна на метода — трик, при който променяме изпълнението на метод, дефиниран в базовия клас, без да променяме сигнатурата на метода. Това по същество замества метода: новият метод, дефиниран в подкласа, се извиква, когато програмата се изпълнява. Обикновено, когато заменяме метод, @Overrideизползва се анотация. Той казва на компилатора да провери сигнатурите на отменения и отменящия метод. И накрая, за да сте сигурни, че вашите Java програми са в съответствие с принципите на ООП, следвайте тези съвети:
  • идентифицирайте основните характеристики на обекта;
  • идентифициране на общи свойства и поведение и използване на наследяване при създаване на класове;
  • използват абстрактни типове за описание на обекти;
  • опитвайте се винаги да скривате методи и полета, свързани с вътрешната реализация на класа.
Коментари
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION