JavaRush /Java блогы /Random-KK /Сыныптар мен интерфейстерді жобалау (мақала аудармасы)
fatesha
Деңгей

Сыныптар мен интерфейстерді жобалау (мақала аудармасы)

Топта жарияланған
Сыныптар мен интерфейстерді жобалау (Мақаланың аудармасы) - 1

Мазмұны

  1. Кіріспе
  2. Интерфейстер
  3. Интерфейс маркерлері
  4. Функционалдық интерфейстер, статикалық әдістер және әдепкі әдістер
  5. Абстрактілі сабақтар
  6. Өзгермейтін (тұрақты) кластар
  7. Анонимді сабақтар
  8. Көріну
  9. Мұрагерлік
  10. Көп тұқым қуалаушылық
  11. Тұқым қуалаушылық және құрамы
  12. Инкапсуляция
  13. Қорытынды сабақтар мен әдістер
  14. Ары қарай не
  15. Бастапқы codeты жүктеп алыңыз

1. КІРІСПЕ

Қандай бағдарламалау тілін пайдалансаңыз да (және Java ерекшелік емес), жақсы дизайн принциптерін сақтау таза, түсінікті және тексерілетін code жазудың кілті болып табылады; сонымен қатар оны ұзақ өмір сүретін және мәселені шешуге оңай қолдау көрсететін етіп жасаңыз. Оқулықтың осы бөлігінде біз Java тілі қамтамасыз ететін негізгі құрылыс блоктарын талқылаймыз және дизайн шешімдерін жақсырақ қабылдауға көмектесу үшін бірнеше дизайн принциптерін енгіземіз. Нақтырақ айтқанда, біз интерфейстер мен интерфейстерді әдепкі әдістерді (Java 8-дегі жаңа мүмкіндік), дерексіз және соңғы сыныптарды, өзгермейтін сыныптарды, мұрагерлік, композицияны және қысқаша тоқталған көріну (немесе қол жетімділік) ережелерін қайта қарастырамыз. 1-бөлім сабақ «Объектілерді қалай құруға және жоюға болады» .

2. ИНТЕРФЕЙСТЕР

Объектілі - бағытталған бағдарламалауда интерфейстер түсінігі келісім-шарттарды әзірлеу үшін негіз болып табылады . Қысқаша айтқанда, интерфейстер әдістер (келісімшарттар) жинағын анықтайды және сол нақты интерфейске қолдау көрсетуді қажет ететін әрбір сынып осы әдістердің іске асырылуын қамтамасыз етуі керек: өте қарапайым, бірақ күшті идея. Көптеген бағдарламалау тілдерінде бір немесе басқа пішінде интерфейстер бар, бірақ әсіресе Java бұл үшін тілдік қолдауды қамтамасыз етеді. Java тіліндегі қарапайым интерфейс анықтамасын қарастырайық.
package com.javacodegeeks.advanced.design;

public interface SimpleInterface {
void performAction();
}
Жоғарыдағы үзіндіде біз шақырған интерфейс SimpleInterface, деп аталатын бір ғана әдісті жариялайды performAction. Интерфейстер мен сыныптардың негізгі айырмашылығы - интерфейстер контакт қандай болуы керек екенін көрсетеді (олар әдісті жариялайды), бірақ олардың орындалуын қамтамасыз етпейді. Дегенмен, Java тіліндегі интерфейстер күрделірек болуы мүмкін: олар кірістірілген интерфейстерді, сыныптарды, санауларды, annotationларды және тұрақтыларды қамтуы мүмкін. Мысалы:
package com.javacodegeeks.advanced.design;

public interface InterfaceWithDefinitions {
    String CONSTANT = "CONSTANT";

    enum InnerEnum {
        E1, E2;
    }

    class InnerClass {
    }

    interface InnerInterface {
        void performInnerAction();
    }

    void performAction();
}
Бұл неғұрлым күрделі мысалда интерфейстер кірістіру құрылымдарына және әдіс мәлімдемелеріне сөзсіз жүктейтін бірнеше шектеулер бар және оларды Java компиляторы орындайды. Біріншіден, тіпті ашық түрде жарияланбаса да, интерфейстегі әрбір әдіс декларациясы жалпыға ортақ (және тек жалпы болуы мүмкін). Осылайша, келесі әдіс декларациялары эквивалентті болып табылады:
public void performAction();
void performAction();
Айта кету керек, интерфейстегі әрбір әдіс абстракт болып жарияланады , тіпті бұл әдіс декларациялары да баламалы:
public abstract void performAction();
public void performAction();
void performAction();
Жарияланған тұрақты өрістерге келетін болсақ, олар жалпыға ортақ болумен қатар, жанама түрде статикалық және соңғы деп белгіленген . Сондықтан келесі мәлімдемелер де баламалы:
String CONSTANT = "CONSTANT";
public static final String CONSTANT = "CONSTANT";
Соңында, кірістірілген сыныптар, интерфейстер немесе санаулар, жалпыға ортақ болудан басқа , сонымен қатар жанама түрде static деп жарияланады . Мысалы, бұл мәлімдемелер мыналарға тең:
class InnerClass {
}

static class InnerClass {
}
Сіз таңдаған стиль - бұл жеке қалау, бірақ интерфейстердің осы қарапайым қасиеттерін білу сізді қажетсіз теруден сақтайды.

3. Интерфейс маркері

Маркер интерфейсі - әдістері немесе басқа кірістірілген құрылымдары жоқ интерфейстің ерекше түрі. Java кітапханасы оны қалай анықтайды:
public interface Cloneable {
}
Интерфейс маркерлері жеке келісім-шарттар емес, бірақ кейбір ерекше белгілерді сыныппен «қосу» немесе «байланыстыру» үшін біршама пайдалы әдіс болып табылады. Мысалы, Cloneable параметріне қатысты сынып клондалатын ретінде белгіленеді, бірақ оны жүзеге асыруға болатын немесе жүзеге асырылатын жол интерфейстің бөлігі емес. Интерфейс маркерінің тағы бір әйгілі және кеңінен қолданылатын мысалы Serializable:
public interface Serializable {
}
Бұл интерфейс сыныпты сериялау және сериядан шығару үшін қолайлы деп белгілейді және қайтадан оны қалай жүзеге асыруға болатынын немесе қажет екенін көрсетпейді. Интерфейс маркерлерінің an objectілі-бағытталған бағдарламалауда өз орны бар, бірақ олар интерфейстің келісім-шарт болу негізгі мақсатын қанағаттандырмайды. 

4. ФУНКЦИОНАЛДЫҚ ИНТЕРФЕЙСТЕР, ӘДІСТЕМЕЛІК ӘДІСТЕР ЖӘНЕ СТАТИКА ӘДІСТЕР

Java 8 шығарылымынан бастап интерфейстер өте қызықты жаңа мүмкіндіктерге ие болды: статикалық әдістер, әдепкі әдістер және ламбдалардан автоматты түрлендіру (функционалдық интерфейстер). Интерфейстер бөлімінде біз Java тіліндегі интерфейстер тек әдістерді жариялай алатынын, бірақ олардың орындалуын қамтамасыз етпейтінін атап өттік. Әдепкі әдіспен бәрі басқаша болады: интерфейс әдепкі кілт сөзімен әдісті белгілей алады және оған енгізуді қамтамасыз ете алады. Мысалы:
package com.javacodegeeks.advanced.design;

public interface InterfaceWithDefaultMethods {
    void performAction();

    default void performDefaulAction() {
        // Implementation here
    }
}
Дана деңгейінде болғандықтан, әдепкі әдістерді әрбір интерфейсті іске асыру арқылы қайта анықтауға болады, бірақ интерфейстер енді статикалық әдістерді де қамтуы мүмкін, мысалы: com.javacodegeeks.advanced.design пакеті;
public interface InterfaceWithDefaultMethods {
    static void createAction() {
        // Implementation here
    }
}
Интерфейстегі енгізуді қамтамасыз ету келісімшарттық бағдарламалаудың барлық мақсатын жоққа шығарады деп айтуға болады. Бірақ бұл мүмкіндіктердің Java тіліне енгізілуінің көптеген себептері бар және олар қаншалықты пайдалы немесе түсініксіз болса да, олар сізге және сіздің пайдалануыңызға арналған. Функционалдық интерфейстер - бұл басқа әңгіме және тілге өте пайдалы толықтырулар болып шықты. Негізінде, функционалды интерфейс - бұл жарияланған бір ғана дерексіз әдіс бар интерфейс. RunnableСтандартты кітапхана интерфейсі осы тұжырымдаманың өте жақсы мысалы болып табылады.
@FunctionalInterface
public interface Runnable {
    void run();
}
Java компиляторы функционалды интерфейстерді басқаша қарастырады және мағынасы бар жерде ламбда функциясын функционалды интерфейсті іске асыруға айналдыра алады. Келесі функцияның сипаттамасын қарастырайық: 
public void runMe( final Runnable r ) {
    r.run();
}
Бұл функцияны Java 7 және одан төменірек нұсқаларында шақыру үшін интерфейстің іске асырылуын қамтамасыз ету керек Runnable(мысалы, анонимді сыныптарды пайдалану), бірақ Java 8-де lambda синтаксисін пайдаланып run() әдісін іске асыруды қамтамасыз ету жеткілікті:
runMe( () -> System.out.println( "Run!" ) );
Сонымен қатар, @FunctionalInterface annotationсы (annotationлар оқулықтың 5-бөлімінде егжей-тегжейлі қарастырылады) компилятор интерфейсте тек бір дерексіз әдіс бар-жоғын тексере алатынын көрсетеді, сондықтан болашақта интерфейске енгізілген кез келген өзгертулер бұл болжамды бұзбайды. .

5. РЕФЕРАТ САБАҚТАР

Java тілі қолдайтын тағы бір қызықты концепция – абстрактілі сыныптар тұжырымдамасы. Абстрактілі сыныптар Java 7-дегі интерфейстерге біршама ұқсас және Java 8-дегі әдепкі әдіс интерфейсіне өте жақын. Кәдімгі сыныптардан айырмашылығы, абстрактілі сыныпты құру мүмкін емес, бірақ оны қосалқы сыныпқа бөлуге болады (толығырақ мәліметтер алу үшін «Мұра» бөлімін қараңыз). Ең бастысы, абстрактілі сыныптар абстрактілі әдістерді қамтуы мүмкін: интерфейс сияқты іске асырусыз әдістің ерекше түрі. Мысалы:
package com.javacodegeeks.advanced.design;

public abstract class SimpleAbstractClass {
    public void performAction() {
        // Implementation here
    }

    public abstract void performAnotherAction();
}
Бұл мысалда класс дерексізSimpleAbstractClass деп жарияланды және бір жарияланған дерексіз әдісті қамтиды. Абстрактілі сыныптар өте пайдалы; іске асыру мәліметтерінің көпшілігі немесе тіпті кейбір бөліктері көптеген ішкі сыныптар арасында ортақ болуы мүмкін. Қалай болғанда да, олар әлі де есікті ашық қалдырады және дерексіз әдістерді қолдана отырып, әрбір ішкі сыныпқа тән мінез-құлықты теңшеуге мүмкіндік береді. Айта кету керек, тек жалпыға ортақ мәлімдемелер болуы мүмкін интерфейстерден айырмашылығы, дерексіз сыныптар дерексіз әдістің көрінуін басқару үшін қол жетімділік ережелерінің толық күшін пайдалана алады.

6. ТЕЗ САБАҚТАР

Қазіргі уақытта бағдарламалық жасақтаманы әзірлеуде өзгермейтіндік барған сайын маңызды болып келеді. Көп ядролы жүйелердің өркендеуі деректерді алмасуға және параллелизмге қатысты көптеген мәселелерді көтерді. Бірақ бір мәселе сөзсіз пайда болды: өзгермелі күйдің шамалы (немесе тіпті жоқ) болуы жақсы кеңейтілуге ​​(масштабтылыққа) және жүйе туралы оңай пайымдауға әкеледі. Өкінішке орай, Java тілі сыныптың өзгермейтіндігіне лайықты қолдау көрсетпейді. Дегенмен, әдістердің комбинациясын қолдана отырып, өзгермейтін сыныптарды жобалау мүмкін болады. Ең алдымен, сыныптың барлық өрістері түпкілікті болуы керек ( соңғы деп белгіленген ). Бұл жақсы бастама, бірақ бұл кепілдік емес. 
package com.javacodegeeks.advanced.design;

import java.util.Collection;

public class ImmutableClass {
    private final long id;
    private final String[] arrayOfStrings;
    private final Collection<String> collectionOfString;
}
Екіншіден, дұрыс инициализацияны қамтамасыз етіңіз: егер өріс жинаққа немесе массивке сілтеме болса, сол өрістерді тікелей конструктор аргументтерінен тағайындамаңыз, оның орнына көшірмелерді жасаңыз. Бұл жинақтың немесе массивтің күйінің одан тыс өзгертілмейтінін қамтамасыз етеді.
public ImmutableClass( final long id, final String[] arrayOfStrings,
        final Collection<String> collectionOfString) {
    this.id = id;
    this.arrayOfStrings = Arrays.copyOf( arrayOfStrings, arrayOfStrings.length );
    this.collectionOfString = new ArrayList<>( collectionOfString );
}
Соңында, дұрыс қол жеткізуді қамтамасыз ету (алғыштар). Коллекциялар үшін өзгермейтіндік орауыш ретінде берілуі керек  Collections.unmodifiableXxx: Массивтермен шынайы өзгермейтіндікті қамтамасыз етудің жалғыз жолы - массивке сілтемені қайтарудың орнына көшірмені қамтамасыз ету. Бұл практикалық тұрғыдан қабылданбауы мүмкін, өйткені ол массивтің өлшеміне өте тәуелді және қоқыс жинағышқа үлкен қысым көрсетуі мүмкін.
public String[] getArrayOfStrings() {
    return Arrays.copyOf( arrayOfStrings, arrayOfStrings.length );
}
Тіпті осы шағын мысалдың өзі өзгермейтіндік әлі Java тіліндегі бірінші дәрежелі азамат емес екендігі туралы жақсы түсінік береді. Егер өзгермейтін сыныпта басқа сыныптың an objectісіне сілтеме жасайтын өріс болса, жағдай күрделенуі мүмкін. Бұл сыныптар да өзгермейтін болуы керек, бірақ мұны қамтамасыз етудің ешқандай жолы жоқ. FindBugs және PMD сияқты бірнеше лайықты Java бастапқы code анализаторлары бар, олар сіздің codeыңызды тексеру және жалпы Java бағдарламалау кемшіліктерін көрсету арқылы үлкен көмек көрсете алады. Бұл құралдар кез келген Java әзірлеушісінің тамаша достары.

7. АНОНИМДЫ СЫНЫПТАР

Java 8-ге дейінгі дәуірде анонимді сыныптар сыныптарды жылдам анықтап, дереу іске қосуды қамтамасыз етудің жалғыз жолы болды. Анонимді сыныптардың мақсаты - стандартты азайту және сыныптарды жазба ретінде көрсетудің қысқа және оңай жолын қамтамасыз ету. Java-де жаңа ағынды шығарудың әдеттегі ескі әдісін қарастырайық:
package com.javacodegeeks.advanced.design;

public class AnonymousClass {
    public static void main( String[] args ) {
        new Thread(
            // Example of creating anonymous class which implements
            // Runnable interface
            new Runnable() {
                @Override
                public void run() {
                    // Implementation here
                }
            }
        ).start();
    }
}
Бұл мысалда Runnableинтерфейсті іске асыру анонимді класс ретінде бірден беріледі. Анонимді сыныптармен байланысты кейбір шектеулер болса да, оларды пайдаланудың негізгі кемшіліктері Java тілі ретінде міндеттейтін өте егжей-тегжейлі құрылымдық синтаксис болып табылады. Тіпті ештеңе жасамайтын анонимді сыныптың өзі жазылған сайын кемінде 5 жол codeты қажет етеді.
new Runnable() {
   @Override
   public void run() {
   }
}
Бақытымызға орай, Java 8, lambda және функционалды интерфейстермен бұл стереотиптердің барлығы жақын арада жойылады, ақырында Java codeын жазу шынымен қысқаша көрінеді.
package com.javacodegeeks.advanced.design;

public class AnonymousClass {
    public static void main( String[] args ) {
        new Thread( () -> { /* Implementation here */ } ).start();
    }
}

8. КӨРІНУ

Біз оқулықтың 1-бөлімінде Java тіліндегі көріну және қол жетімділік ережелері туралы біраз әңгімелестік. Бұл бөлімде біз бұл тақырыпты қайта қарастырамыз, бірақ ішкі сыныптау контекстінде. Сыныптар мен интерфейстерді жобалау (Мақаланың аудармасы) - 2Әртүрлі деңгейлердегі көріну сыныптарға басқа сыныптарды немесе интерфейстерді (мысалы, олар әртүрлі бумаларда болса немесе бір-біріне кірістірілген болса) немесе ішкі сыныптарға ата-аналарының әдістерін, конструкторларын және өрістерін көруге және оларға қатынасуға мүмкіндік береді немесе оларға жол бермейді. Келесі бөлімде мұрагерлік, біз мұны әрекетте көреміз.

9. МҰРА АЛУ

Мұрагерлік an objectілі-бағытталған бағдарламалаудың негізгі концепцияларының бірі болып табылады, байланыстар класын құру үшін негіз болады. Көріну және қол жетімділік ережелерімен біріктірілген мұра сыныптарды кеңейтуге және қолдауға болатын иерархияға құрастыруға мүмкіндік береді. Тұжырымдама деңгейінде Java тіліндегі мұра тектік сыныппен бірге қосалқы класс пен extensions кілт сөзі арқылы жүзеге асырылады. Ішкі сынып ата-аналық сыныптың барлық жалпы және қорғалған элементтерін мұра етеді. Қосымша, егер екеуі де (ішкі сынып пен сынып) бір бумада болса, ішкі сынып өзінің ата-аналық класының бума-жеке элементтерін иеленеді. Айтуынша, сіз не құрастыруға тырыссаңыз да, сынып көпшілікке немесе оның ішкі сыныптарына ашатын әдістердің ең аз жиынтығын ұстану өте маңызды. Мысалы, көріну деңгейлерінің айырмашылығын және олардың әсерлерін көрсету үшін сыныпты Parentжәне оның ішкі сыныбын қарастырайық .Child
package com.javacodegeeks.advanced.design;

public class Parent {
    // Everyone can see it
    public static final String CONSTANT = "Constant";

    // No one can access it
    private String privateField;
    // Only subclasses can access it
    protected String protectedField;

    // No one can see it
    private class PrivateClass {
    }

    // Only visible to subclasses
    protected interface ProtectedInterface {
    }

    // Everyone can call it
    public void publicAction() {
    }

    // Only subclass can call it
    protected void protectedAction() {
    }

    // No one can call it
    private void privateAction() {
    }

    // Only subclasses in the same package can call it
    void packageAction() {
    }
}
package com.javacodegeeks.advanced.design;

// Resides in the same package as parent class
public class Child extends Parent implements Parent.ProtectedInterface {
    @Override
    protected void protectedAction() {
        // Calls parent's method implementation
        super.protectedAction();
    }

    @Override
    void packageAction() {
        // Do nothing, no call to parent's method implementation
    }

    public void childAction() {
        this.protectedField = "value";
    }
}
Мұрагерлік - бұл Java-ға тән көптеген егжей-тегжейлері бар өте үлкен тақырып. Дегенмен, ұстануға оңай және сынып иерархиясының қысқалығын сақтауда ұзақ жолға бара алатын бірнеше ережелер бар. Java тілінде әрбір ішкі сынып түпкілікті деп жарияланбаса, ата-анасының кез келген мұраланған әдістерін қайта анықтай алады. Дегенмен, әдісті қайта анықталған деп белгілейтін арнайы синтаксис немесе кілт сөз жоқ, бұл шатасуға әкелуі мүмкін. Сондықтан @Override annotationсы енгізілді : сіздің мақсатыңыз мұраланған әдісті қайта анықтау болса, оны қысқаша көрсету үшін @Override annotationсын пайдаланыңыз . Java әзірлеушілері дизайнда үнемі тап болатын тағы бір дилемма интерфейстерді жүзеге асырумен салыстырғанда класс иерархияларын (нақты немесе дерексіз класстармен) құру болып табылады. Мүмкіндігінше сыныптарға немесе дерексіз сыныптарға қарағанда интерфейстерді таңдауды ұсынамыз. Интерфейстер жеңілірек, сынау және қызмет көрсету оңайырақ, сонымен қатар енгізу өзгерістерінің жанама әсерлерін азайтады. Java стандартты кітапханасында прокси сыныптарын жасау сияқты көптеген озық бағдарламалау әдістері негізінен интерфейстерге сүйенеді.

10. КӨПТЕГЕН ТҰРАҒАЛУ

C++ және кейбір басқа тілдерден айырмашылығы, Java бірнеше мұраға қолдау көрсетпейді: Java тілінде әрбір сыныпта бір ғана тікелей ата-ана болуы мүмкін (класс Objectиерархияның жоғарғы жағында). Дегенмен, сынып бірнеше интерфейстерді жүзеге асыра алады, сондықтан интерфейсті стектеу Java-да бірнеше мұраға қол жеткізудің (немесе имитациялаудың) жалғыз жолы болып табылады.
package com.javacodegeeks.advanced.design;

public class MultipleInterfaces implements Runnable, AutoCloseable {
    @Override
    public void run() {
        // Some implementation here
    }

    @Override
    public void close() throws Exception {
       // Some implementation here
    }
}
Бірнеше интерфейстерді енгізу шын мәнінде өте күшті, бірақ көбінесе іске асыруды қайта-қайта пайдалану қажеттілігі Java-ның бірнеше мұраға қолдауының жоқтығын жеңудің тәсілі ретінде терең класс иерархиясына әкеледі. 
public class A implements Runnable {
    @Override
    public void run() {
        // Some implementation here
    }
}
// Class B wants to inherit the implementation of run() method from class A.
public class B extends A implements AutoCloseable {
    @Override
    public void close() throws Exception {
       // Some implementation here
    }
}
// Class C wants to inherit the implementation of run() method from class A
// and the implementation of close() method from class B.
public class C extends B implements Readable {
    @Override
    public int read(java.nio.CharBuffer cb) throws IOException {
       // Some implementation here
    }
}
Және т.б.... Java 8 нұсқасының жақында шығарылымы әдепкі әдісті енгізу мәселесін біршама шешеді. Әдепкі әдістерге байланысты интерфейстер іс жүзінде келісімшартты ғана емес, сонымен қатар іске асыруды да қамтамасыз етеді. Сондықтан, осы интерфейстерді жүзеге асыратын сыныптар да осы енгізілген әдістерді автоматты түрде мұраға алады. Мысалы:
package com.javacodegeeks.advanced.design;

public interface DefaultMethods extends Runnable, AutoCloseable {
    @Override
    default void run() {
        // Some implementation here
    }

    @Override
    default void close() throws Exception {
       // Some implementation here
    }
}

// Class C inherits the implementation of run() and close() methods from the
// DefaultMethods interface.
public class C implements DefaultMethods, Readable {
    @Override
    public int read(java.nio.CharBuffer cb) throws IOException {
       // Some implementation here
    }
}
Бірнеше мұра өте күшті, бірақ сонымен бірге қауіпті құрал екенін есте сақтаңыз. Әйгілі «Өлім гауһары» мәселесі жиі бірнеше мұраны жүзеге асырудағы негізгі кемшілік ретінде аталып, әзірлеушілерді сынып иерархияларын өте мұқият жобалауға мәжбүр етеді. Өкінішке орай, әдепкі әдістері бар Java 8 интерфейстері де осы ақаулардың құрбаны болады.
interface A {
    default void performAction() {
    }
}

interface B extends A {
    @Override
    default void performAction() {
    }
}

interface C extends A {
    @Override
    default void performAction() {
    }
}
Мысалы, келесі code үзіндісі компиляцияланбайды:
// E is not compilable unless it overrides performAction() as well
interface E extends B, C {
}
Осы кезде Java тілі ретінде әрқашан an objectіге бағытталған бағдарламалаудың бұрыштық жағдайларын болдырмауға тырысты, бірақ тіл дамып келе жатқанда, бұл жағдайлардың кейбірі кенеттен пайда бола бастады. 

11. МҰРАҒАЛУ ЖӘНЕ ҚҰРАМЫ

Бақытымызға орай, мұра сіздің сыныпты жобалаудың жалғыз жолы емес. Көптеген әзірлеушілер мұраға қарағанда әлдеқайда жақсы деп санайтын тағы бір балама - композиция. Идея өте қарапайым: сыныптардың иерархиясын құрудың орнына, олар басқа сыныптардан құралуы керек. Мына мысалды қарастырайық:
// E is not compilable unless it overrides performAction() as well
interface E extends B, C {
}
Класс Vehicleқозғалтқыш пен доңғалақтардан тұрады (оның үстіне қарапайымдылық үшін қалдырылған көптеген басқа бөліктер). VehicleДегенмен, сыныпты да қозғалтқыш  деп айтуға болады , сондықтан оны мұрагерлік арқылы жобалауға болады.
public class Vehicle extends Engine {
    private Wheels[] wheels;
    // ...
}
Қандай дизайн шешімі дұрыс болады? Жалпы негізгі нұсқаулар IS-A (is) және HAS-A (құрамында) принциптері ретінде белгілі. IS-A – мұрагерлік қатынас: ішкі сынып сонымен қатар ата-аналық сыныптың класс сипаттамасын және негізгі сыныптың вариациясын қанағаттандырады. ішкі сынып) өзінің ата-анасын кеңейтеді. Бір нысан басқасын кеңейтетінін білгіңіз келсе, сәйкестік сынамасын орындаңыз - IS -A (is).") Сондықтан, HAS-A композициялық қатынас болып табылады: сынып көптеген себептерге байланысты IS-A принципіне қарағанда көп жағдайда жақсы жұмыс істейтін нысанға ие (немесе құрамында) бар: 
  • Дизайн неғұрлым икемді;
  • Үлгі тұрақтырақ, себебі өзгеріс класс иерархиясы арқылы таралмайды;
  • Класс пен оның құрамы ата-ана мен оның қосалқы сыныбын тығыз байланыстыратын композициямен салыстырғанда еркін байланысқан.
  • Сыныптағы логикалық ойлау жүйесі қарапайым, өйткені оның барлық тәуелділіктері оған бір жерде кіреді. 
Қарамастан, мұрагерлік өз орны бар және бар бірқатар дизайн мәселелерін әртүрлі жолдармен шешеді, сондықтан оны елемеуге болмайды. Нысанға бағытталған модельді жобалау кезінде осы екі баламаны есте сақтаңыз.

12. ИНКАПСУЛЯЦИЯ.

Объектіге бағытталған бағдарламалаудағы инкапсуляция концепциясы барлық іске асыру мәліметтерін (мысалы, жұмыс режимі, ішкі әдістер және т.б.) сыртқы әлемнен жасыру болып табылады. Инкапсуляцияның артықшылығы - техникалық қызмет көрсету және өзгерту оңай. Класстың ішкі іске асырылуы жасырын, сынып деректерімен жұмыс тек сыныптың жалпы әдістері арқылы жүзеге асады (көп адамдар пайдаланатын кітапхананы немесе құрылымды жасап жатсаңыз, нақты мәселе). Java тіліндегі инкапсуляцияға көріну және қол жетімділік ережелері арқылы қол жеткізіледі. Java тілінде өрістерді ешқашан тікелей ашпау ең жақсы тәжірибе болып саналады, тек алушылар мен орнатушылар арқылы (өрістер түпкілікті деп белгіленбесе). Мысалы:
package com.javacodegeeks.advanced.design;

public class Encapsulation {
    private final String email;
    private String address;

    public Encapsulation( final String email ) {
        this.email = email;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getEmail() {
        return email;
    }
}
Бұл мысал Java тіліндегі JavaBeans деп аталатын нәрсені еске түсіреді : стандартты Java сыныптары конвенциялар жиынтығына сәйкес жазылған, олардың бірі өрістерге тек getter және setter әдістерін қолдану арқылы қол жеткізуге мүмкіндік береді. Мұрагерлік бөлімде жоғарыда атап өткеніміздей, инкапсуляция принциптерін қолдана отырып, әрқашан сыныптағы ең төменгі жариялылық келісім-шартын ұстаныңыз. Жалпыға ортақ болмауы керек нәрсенің бәрі жеке (немесе сіз шешіп жатқан мәселеге байланысты қорғалған/пакет жеке) болуы керек. Бұл сізге үзіліссіз өзгертулер енгізбей (немесе кем дегенде оларды азайтпай) дизайнға еркіндік беру арқылы ұзақ мерзімді перспективада өтеледі. 

13. ҚОРЫТЫНДЫ САБАҚТАР МЕН ӘДІСТЕР

Java тілінде сыныптың басқа сыныптың қосалқы сыныбына айналуын болдырмаудың жолы бар: басқа класс түпкілікті деп жариялануы керек. 
package com.javacodegeeks.advanced.design;

public final class FinalClass {
}
Әдіс мәлімдемесіндегі  бірдей соңғы кілт сөз ішкі сыныптардың әдісті қайта анықтауына жол бермейді.
package com.javacodegeeks.advanced.design;

public class FinalMethod {
    public final void performAction() {
    }
}
Кластың немесе әдістердің түпкілікті болуы немесе болмауын шешудің жалпы ережелері жоқ. Қорытынды сыныптар мен әдістер кеңейтімді шектейді және сыныпты мұраға алу керек пе, жоқ па, немесе болашақта әдісті жою керек пе, жоқ па, алдын ала ойлану өте қиын. Бұл кітапхана әзірлеушілері үшін өте маңызды, өйткені мұндай дизайн шешімдері кітапхананың қолдану мүмкіндігін айтарлықтай шектеуі мүмкін. Java стандартты кітапханасында соңғы сыныптардың бірнеше мысалдары бар, олардың ең танымалы String класы. Ерте кезеңде бұл шешім әзірлеушілердің жолды іске асырудың жеке, «жақсы» шешімін табу әрекеттерінің алдын алу үшін қабылданды. 

14. КЕЛЕСІ НЕ

Сабақтың бұл бөлімінде біз Java тілінде an objectіге бағытталған бағдарламалау ұғымдарын қарастырдық. Біз сондай-ақ келісімшарттық бағдарламалауды жылдам қарастырдық, кейбір функционалдық тұжырымдамаларға тоқталып, тілдің уақыт өте келе қалай дамығанын көрдік. Сабақтың келесі бөлігінде біз генериктермен танысамыз және олар бағдарламалаудағы қауіпсіздік типіне деген көзқарасымызды қалай өзгертетінін көреміз. 

15. КӨЗ КОДЫН ЖҮКТЕП АЛУ

Дереккөзді мына жерден жүктеп алуға болады - advanced-java-part-3 Source: How to design Classes an
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION