JavaRush /Java Blogu /Random-AZ /Siniflərin və interfeyslərin dizaynı (məqalənin tərcüməsi...
fatesha
Səviyyə

Siniflərin və interfeyslərin dizaynı (məqalənin tərcüməsi)

Qrupda dərc edilmişdir
Siniflərin və interfeyslərin dizaynı (Məqalənin tərcüməsi) - 1

Məzmun

  1. Giriş
  2. İnterfeyslər
  3. İnterfeys markerləri
  4. Funksional interfeyslər, statik metodlar və standart metodlar
  5. Abstrakt dərslər
  6. Dəyişməz (daimi) siniflər
  7. Anonim siniflər
  8. Görünüş
  9. Miras
  10. Çoxlu miras
  11. Varislik və tərkibi
  12. İnkapsulyasiya
  13. Yekun dərslər və üsullar
  14. Sonra nə var
  15. Mənbə kodunu yükləyin

1. GİRİŞ

Hansı proqramlaşdırma dilindən istifadə etməyinizdən asılı olmayaraq (və Java da istisna deyil), yaxşı dizayn prinsiplərinə riayət etmək təmiz, başa düşülən və yoxlanıla bilən kod yazmağın açarıdır; və həmçinin uzun ömürlü olmaq və problemin həllini asanlıqla dəstəkləmək üçün yaradın. Dərsliyin bu hissəsində biz Java dilinin təmin etdiyi əsas tikinti bloklarını müzakirə edəcəyik və daha yaxşı dizayn qərarları qəbul etməyinizə kömək etmək üçün bir neçə dizayn prinsipini təqdim edəcəyik. Daha dəqiq desək, biz standart metodlardan (Java 8-də yeni xüsusiyyət), abstrakt və yekun siniflərdən, dəyişməz siniflərdən, mirasdan, kompozisiyadan istifadə edən interfeys və interfeysləri müzakirə edəcəyik və qısaca toxunduğumuz görünmə (və ya əlçatanlıq) qaydalarına yenidən baxacağıq. 1-ci hissə dərsi "Obyektləri necə yaratmaq və məhv etmək" .

2. İNTERFEYSLER

Obyekt yönümlü proqramlaşdırmada interfeys anlayışı müqavilələrin inkişafı üçün əsas təşkil edir . Bir sözlə, interfeyslər bir sıra metodlar (müqavilələr) müəyyən edir və həmin xüsusi interfeys üçün dəstək tələb edən hər bir sinif həmin metodların həyata keçirilməsini təmin etməlidir: kifayət qədər sadə, lakin güclü ideya. Bir çox proqramlaşdırma dillərində bu və ya digər formada interfeyslər var, lakin xüsusilə Java bunun üçün dil dəstəyi təmin edir. Java-da sadə interfeys tərifinə nəzər salaq.
package com.javacodegeeks.advanced.design;

public interface SimpleInterface {
void performAction();
}
Yuxarıdakı fraqmentdə çağırdığımız interfeys SimpleInterfaceyalnız bir metodu elan edir performAction. İnterfeyslər və siniflər arasındakı əsas fərq ondan ibarətdir ki, interfeyslər kontaktın nə olması lazım olduğunu göstərir (onlar bir metodu elan edirlər), lakin onların həyata keçirilməsini təmin etmirlər. Bununla belə, Java-da interfeyslər daha mürəkkəb ola bilər: onlara iç-içə interfeyslər, siniflər, saylar, annotasiyalar və sabitlər daxil ola bilər. Misal üçün:
package com.javacodegeeks.advanced.design;

public interface InterfaceWithDefinitions {
    String CONSTANT = "CONSTANT";

    enum InnerEnum {
        E1, E2;
    }

    class InnerClass {
    }

    interface InnerInterface {
        void performInnerAction();
    }

    void performAction();
}
Bu daha mürəkkəb nümunədə, interfeyslərin qeyd-şərtsiz daxili konstruksiyalara və Java kompilyatorunun tətbiq etdiyi metod bəyanlarına tətbiq etdiyi bir neçə məhdudiyyət var. Əvvəla, açıq şəkildə elan edilməsə belə, interfeysdəki hər bir metod bəyannaməsi açıqdır ( və yalnız ictimai ola bilər). Beləliklə, aşağıdakı metod bəyannamələri ekvivalentdir:
public void performAction();
void performAction();
Qeyd etmək lazımdır ki, interfeysdəki hər bir metod mücərrəd elan edilir və hətta bu metod bəyannamələri də ekvivalentdir:
public abstract void performAction();
public void performAction();
void performAction();
Elan edilmiş daimi sahələrə gəldikdə, onlar ictimai olmaqla yanaşı , həm də dolayısı ilə statikdiryekun olaraq qeyd olunur . Beləliklə, aşağıdakı bəyannamələr də ekvivalentdir:
String CONSTANT = "CONSTANT";
public static final String CONSTANT = "CONSTANT";
Nəhayət, iç-içə siniflər, interfeyslər və ya saylar ictimai olmaqla yanaşı , həm də dolayısı ilə statik elan edilir . Məsələn, bu bəyannamələr də aşağıdakılara bərabərdir:
class InnerClass {
}

static class InnerClass {
}
Seçdiyiniz üslub şəxsi seçimdir, lakin interfeyslərin bu sadə xüsusiyyətlərini bilmək sizi lazımsız yazmaqdan xilas edə bilər.

3. İnterfeys markeri

Marker interfeysi metodları və ya digər iç içə konstruksiyaları olmayan xüsusi bir interfeys növüdür. Java kitabxanası onu necə müəyyənləşdirir:
public interface Cloneable {
}
İnterfeys markerləri özlüyündə müqavilələr deyil, lakin müəyyən xüsusiyyəti siniflə "qoşmaq" və ya "əlaqələndirmək" üçün bir qədər faydalı texnikadır. Məsələn, Cloneable ilə əlaqədar olaraq , sinif klonlaşdırıla bilən kimi qeyd olunur, lakin bunun həyata keçirilə biləcəyi və ya edilməli olduğu yol interfeysin bir hissəsi deyil. İnterfeys markerinin çox məşhur və geniş istifadə olunan başqa bir nümunəsi Serializable:
public interface Serializable {
}
Bu interfeys sinfi seriallaşdırma və sıradan çıxarma üçün uyğun olaraq qeyd edir və yenə də bunun necə həyata keçirilə biləcəyini və ya edilməli olduğunu göstərmir. İnterfeys markerlərinin obyekt yönümlü proqramlaşdırmada öz yeri var, baxmayaraq ki, onlar interfeysin müqavilə olması kimi əsas məqsədini təmin etmir. 

4. FUNKSİONAL İNTERFESYONLAR, DEFORT ÜSULLAR VƏ STATİK ÜSULLAR

Java 8-in buraxılışından bəri interfeyslər çox maraqlı yeni xüsusiyyətlər qazanmışdır: statik metodlar, standart metodlar və lambdalardan avtomatik çevrilmə (funksional interfeyslər). İnterfeyslər bölməsində biz Java-dakı interfeyslərin yalnız metodları elan edə biləcəyini, lakin onların həyata keçirilməsini təmin etmədiyini vurğuladıq. Defolt metodla hər şey fərqlidir: interfeys standart açar sözlə metodu qeyd edə və bunun üçün tətbiq təmin edə bilər. Misal üçün:
package com.javacodegeeks.advanced.design;

public interface InterfaceWithDefaultMethods {
    void performAction();

    default void performDefaulAction() {
        // Implementation here
    }
}
Nümunə səviyyəsində olduğundan, defolt metodlar hər bir interfeys tətbiqi ilə ləğv edilə bilər, lakin indi interfeyslərə statik metodlar da daxil ola bilər, məsələn: paket com.javacodegeeks.advanced.design;
public interface InterfaceWithDefaultMethods {
    static void createAction() {
        // Implementation here
    }
}
Demək olar ki, interfeysdə tətbiqin təmin edilməsi müqavilə proqramlaşdırmasının bütün məqsədini məğlub edir. Lakin bu xüsusiyyətlərin Java dilinə daxil olmasının bir çox səbəbi var və nə qədər faydalı və ya çaşdırıcı olsalar da, onlar sizin və istifadəniz üçün mövcuddur. Funksional interfeyslər fərqli bir hekayədir və dilə çox faydalı əlavələr olduğunu sübut etdi. Əsasən, funksional interfeys, yalnız bir mücərrəd metodun elan edildiyi interfeysdir. RunnableStandart kitabxana interfeysi bu konsepsiyanın çox yaxşı nümunəsidir.
@FunctionalInterface
public interface Runnable {
    void run();
}
Java kompilyatoru funksional interfeyslərə fərqli yanaşır və məntiqli olduğu yerdə lambda funksiyasını funksional interfeys tətbiqinə çevirə bilər. Aşağıdakı funksiya təsvirini nəzərdən keçirək: 
public void runMe( final Runnable r ) {
    r.run();
}
Java 7 və daha aşağı versiyalarda bu funksiyanı çağırmaq üçün interfeysin tətbiqi təmin edilməlidir Runnable(məsələn, anonim siniflərdən istifadə etməklə), lakin Java 8-də lambda sintaksisindən istifadə edərək run() metodunun həyata keçirilməsini təmin etmək kifayətdir:
runMe( () -> System.out.println( "Run!" ) );
Bundan əlavə, @FunctionalInterface annotasiyası (annotasiyalar təlimatın 5-ci hissəsində ətraflı təsvir olunacaq) göstəriş verir ki, tərtibçi interfeysdə yalnız bir mücərrəd metoddan ibarət olub-olmadığını yoxlaya bilər, ona görə də gələcəkdə interfeysə edilən hər hansı dəyişiklik bu fərziyyəni pozmayacaq. .

5. REFERAT DƏRSLƏR

Java dili tərəfindən dəstəklənən digər maraqlı konsepsiya abstrakt siniflər anlayışıdır. Mücərrəd siniflər Java 7-dəki interfeyslərə bir qədər bənzəyir və Java 8-dəki standart metod interfeysinə çox yaxındır. Adi siniflərdən fərqli olaraq, mücərrəd sinif yaradıla bilməz, lakin o, alt siniflərə bölünə bilər (daha ətraflı məlumat üçün Miras bölməsinə baxın). Daha da əhəmiyyətlisi, mücərrəd siniflər mücərrəd metodları ehtiva edə bilər: interfeys kimi tətbiqi olmayan xüsusi bir metod növü. Misal üçün:
package com.javacodegeeks.advanced.design;

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

    public abstract void performAnotherAction();
}
Bu nümunədə sinif mücərrədSimpleAbstractClass elan edilir və elan edilmiş bir abstrakt metoddan ibarətdir. Abstrakt siniflər çox faydalıdır; həyata keçirmə təfərrüatlarının əksəriyyəti və ya hətta bəzi hissələri bir çox alt siniflər arasında paylaşıla bilər. Nə olursa olsun, onlar hələ də qapını açıq qoyurlar və mücərrəd üsullardan istifadə edərək hər bir alt sinifə xas olan davranışı fərdiləşdirməyə imkan verirlər. Qeyd etmək lazımdır ki, yalnız ictimai bəyannamələri ehtiva edə bilən interfeyslərdən fərqli olaraq, mücərrəd siniflər mücərrəd metodun görünməsinə nəzarət etmək üçün əlçatanlıq qaydalarının tam gücündən istifadə edə bilər.

6. TECILI DERSLER

Dəyişməzlik hal-hazırda proqram təminatının hazırlanmasında getdikcə daha çox əhəmiyyət kəsb edir. Çoxnüvəli sistemlərin yüksəlişi məlumat mübadiləsi və paralellik ilə bağlı bir çox məsələləri gündəmə gətirib. Ancaq bir problem mütləq ortaya çıxdı: dəyişkən vəziyyətin az olması (və ya hətta olmaması) sistem haqqında daha yaxşı genişlənməyə (miqyaslılığa) və asan əsaslandırmaya gətirib çıxarır. Təəssüf ki, Java dili sinfin dəyişməzliyi üçün layiqli dəstək vermir. Bununla belə, texnikaların kombinasiyasından istifadə etməklə, dəyişməz sinifləri dizayn etmək mümkün olur. İlk növbədə, sinfin bütün sahələri yekun olmalıdır ( yekun olaraq qeyd olunur ). Bu yaxşı başlanğıcdır, lakin heç bir zəmanət vermir. 
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;
}
İkincisi, düzgün inisializasiyanı təmin edin: əgər sahə kolleksiyaya və ya massiləyə istinaddırsa, bu sahələri birbaşa konstruktor arqumentlərindən təyin etməyin, əvəzinə surətləri çıxarın. Bu, kolleksiyanın və ya massivin vəziyyətinin ondan kənarda dəyişdirilməməsini təmin edəcək.
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 );
}
Və nəhayət, düzgün girişin təmin edilməsi (alıcılar). Kolleksiyalar üçün dəyişməzlik sarğı kimi təqdim edilməlidir  Collections.unmodifiableXxx: Massivlərlə həqiqi dəyişməzliyi təmin etməyin yeganə yolu massivə istinadı qaytarmaq əvəzinə surəti təqdim etməkdir. Bu, praktiki baxımdan məqbul olmaya bilər, çünki bu, massivin ölçüsündən çox asılıdır və zibil kollektoruna böyük təzyiq göstərə bilər.
public String[] getArrayOfStrings() {
    return Arrays.copyOf( arrayOfStrings, arrayOfStrings.length );
}
Hətta bu kiçik nümunə də yaxşı bir fikir verir ki, dəyişməzlik hələ Java-da birinci dərəcəli vətəndaş deyil. Dəyişməz sinfin başqa sinfin obyektinə istinad edən sahəsi varsa, işlər çətinləşə bilər. Həmin siniflər də dəyişməz olmalıdır, lakin bunu təmin etmək üçün heç bir yol yoxdur. FindBugs və PMD kimi bir neçə layiqli Java mənbə kodu analizatorları var ki, bunlar kodunuzu yoxlamaq və ümumi Java proqramlaşdırma qüsurlarını göstərməklə çox kömək edə bilər. Bu alətlər istənilən Java tərtibatçısının əla dostlarıdır.

7. ANONİM DERSLER

Java 8-dən əvvəlki dövrdə, anonim siniflər siniflərin tez müəyyən edilməsini və dərhal yaradılmasını təmin etmək üçün yeganə yol idi. Anonim siniflərin məqsədi qazanc səviyyəsini azaltmaq və sinifləri rekord kimi təqdim etmək üçün qısa və asan bir yol təqdim etmək idi. Gəlin Java-da yeni mövzu yaratmaq üçün tipik köhnə üsula nəzər salaq:
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();
    }
}
Bu nümunədə interfeysin həyata keçirilməsi Runnableanonim sinif kimi dərhal təmin edilir. Anonim siniflərlə bağlı bəzi məhdudiyyətlər olsa da, onlardan istifadənin əsas çatışmazlıqları Java-nın bir dil olaraq məcbur etdiyi yüksək ətraflı konstruksiya sintaksisidir. Heç nə etməyən sadəcə anonim sinif belə hər yazılan zaman ən azı 5 sətir kod tələb edir.
new Runnable() {
   @Override
   public void run() {
   }
}
Xoşbəxtlikdən, Java 8, lambda və funksional interfeyslərlə bütün bu stereotiplər tezliklə yox olacaq, nəhayət Java kodunun yazılması həqiqətən də qısa görünəcək.
package com.javacodegeeks.advanced.design;

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

8. GÖRÜNÜRLÜK

Biz artıq dərsliyin 1-ci hissəsində Java-da görünmə və əlçatanlıq qaydaları haqqında bir az danışdıq. Bu hissədə biz bu mövzuya yenidən baxacağıq, lakin alt təsnifat kontekstində. Siniflərin və interfeyslərin dizaynı (Məqalənin tərcüməsi) - 2Fərqli səviyyələrdə görünmə siniflərə digər sinifləri və ya interfeysləri (məsələn, onlar müxtəlif paketlərdədirsə və ya bir-biri ilə iç-içədirsə) görməyə və ya alt siniflərə valideynlərinin metodlarını, konstruktorlarını və sahələrini görməyə və onlara daxil olmağa imkan verir və ya qarşısını alır. Növbəti bölmədə, miras, biz bunu hərəkətdə görəcəyik.

9. MİRAS

Varislik, münasibətlər sinfinin qurulması üçün əsas rolunu oynayan obyekt yönümlü proqramlaşdırmanın əsas anlayışlarından biridir. Görünüş və əlçatanlıq qaydaları ilə birlikdə miras sinifləri genişləndirilə və saxlanıla bilən bir iyerarxiya şəklində tərtib etməyə imkan verir. Konseptual səviyyədə Java-da varislik alt sinifdən və ana siniflə birlikdə genişləndirir açar sözündən istifadə etməklə həyata keçirilir. Alt sinif ana sinfin bütün ictimai və qorunan elementlərini miras alır. Bundan əlavə, hər ikisi (alt sinif və sinif) eyni paketdədirsə, alt sinif öz ana sinifinin paket-özəl elementlərini miras alır. Bununla yanaşı, nə dizayn etməyə çalışmağınızdan asılı olmayaraq, bir sinfin ictimaiyyətə və ya alt siniflərinə təqdim etdiyi minimum metodlar dəstinə sadiq qalmaq çox vacibdir. Məsələn, görünmə səviyyələrindəki fərqi və onların təsirlərini nümayiş etdirmək üçün sinfə Parentvə onun alt sinfinə baxaq .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";
    }
}
Varislik özlüyündə çox böyük bir mövzudur, Java-ya xas olan çoxlu incə detallara malikdir. Bununla belə, riayət etmək asan olan və sinif iyerarxiyasının qısalığını saxlamaq üçün uzun bir yol keçə bilən bir neçə qayda var. Java-da hər bir alt sinif, son elan edilmədiyi təqdirdə, valideyninin hər hansı irsi üsullarını ləğv edə bilər. Bununla belə, metodu ləğv edilmiş kimi qeyd etmək üçün xüsusi sintaksis və ya açar söz yoxdur, bu da çaşqınlığa səbəb ola bilər. Buna görə @Override annotasiyası təqdim edildi : məqsədiniz irsi metodu ləğv etmək olduqda, onu qısa şəkildə göstərmək üçün @Override annotasiyasından istifadə edin . Java tərtibatçılarının dizaynda daim qarşılaşdıqları digər dilemma, interfeyslərin həyata keçirilməsinə qarşı sinif iyerarxiyalarının (konkret və ya abstrakt siniflərlə) qurulmasıdır. Mümkün olduqda siniflər və ya abstrakt siniflər üzərində interfeyslərə üstünlük verməyi şiddətlə tövsiyə edirik. İnterfeyslər daha yüngüldür, sınaqdan keçirmək və saxlamaq daha asandır, həmçinin tətbiq dəyişikliklərinin yan təsirlərini minimuma endirir. Java standart kitabxanasında proxy sinifləri yaratmaq kimi bir çox qabaqcıl proqramlaşdırma texnikası əsasən interfeyslərə əsaslanır.

10. ÇOXLU VİRASLIQ

C++ və bəzi digər dillərdən fərqli olaraq, Java çoxlu varisliyi dəstəkləmir: Java-da hər bir sinfin yalnız bir birbaşa valideyni ola bilər (sinf Objectiyerarxiyanın yuxarısında yerləşir). Bununla belə, bir sinif birdən çox interfeys həyata keçirə bilər və beləliklə, interfeysin yığılması Java-da çoxsaylı miras əldə etmək (və ya simulyasiya etmək) üçün yeganə yoldur.
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
    }
}
Çoxsaylı interfeyslərin tətbiqi əslində kifayət qədər güclüdür, lakin tez-tez tətbiqetmədən dəfələrlə istifadə etmək ehtiyacı Java-nın çoxsaylı irsiyyət dəstəyinin çatışmazlığını aradan qaldırmaq üçün bir yol kimi dərin sinif iyerarxiyasına gətirib çıxarır. 
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
    }
}
Və s... Java 8-in son buraxılışı standart metod inyeksiyası ilə bağlı problemi bir qədər həll edir. Defolt üsullara görə interfeyslər əslində təkcə müqavilə deyil, həm də həyata keçirməyi təmin edir. Buna görə də, bu interfeysləri həyata keçirən siniflər də bu həyata keçirilən metodları avtomatik olaraq miras alacaqlar. Misal üçün:
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
    }
}
Unutmayın ki, çoxsaylı miras çox güclü, lakin eyni zamanda təhlükəli bir vasitədir. Məşhur “Ölüm almazı” problemi tez-tez çoxlu mirasın həyata keçirilməsində əsas qüsur kimi qeyd edilir və tərtibatçıları sinif iyerarxiyalarını çox diqqətlə tərtib etməyə məcbur edir. Təəssüf ki, standart metodlara malik Java 8 interfeysləri də bu qüsurların qurbanı olur.
interface A {
    default void performAction() {
    }
}

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

interface C extends A {
    @Override
    default void performAction() {
    }
}
Məsələn, aşağıdakı kod parçası tərtib edilməyəcək:
// E is not compilable unless it overrides performAction() as well
interface E extends B, C {
}
Bu nöqtədə demək ədalətli olar ki, Java bir dil olaraq həmişə obyekt yönümlü proqramlaşdırmanın künc hallardan qaçmağa çalışıb, lakin dil inkişaf etdikcə bu halların bəziləri birdən-birə görünməyə başlayıb. 

11. İRSƏ VƏ TƏRKİB

Xoşbəxtlikdən, miras sinifinizi dizayn etməyin yeganə yolu deyil. Bir çox tərtibatçının mirasdan daha yaxşı olduğuna inandığı başqa bir alternativ kompozisiyadır. İdeya çox sadədir: siniflərin iyerarxiyasını yaratmaq əvəzinə, onları başqa siniflərdən təşkil etmək lazımdır. Bu misala baxaq:
// E is not compilable unless it overrides performAction() as well
interface E extends B, C {
}
Sinif Vehiclemühərrikdən və təkərlərdən (əlavə olaraq sadəlik üçün kənara qoyulmuş bir çox digər hissələrdən) ibarətdir. Bununla belə, bir sinifin də bir mühərrik olduğunu söyləmək olar Vehicle, ona görə də mirasdan istifadə edərək dizayn edilə bilər. 
public class Vehicle extends Engine {
    private Wheels[] wheels;
    // ...
}
Hansı dizayn həlli düzgün olardı? Ümumi əsas təlimatlar IS-A (is) və HAS-A (tərkib edir) prinsipləri kimi tanınır. IS-A irsiyyət əlaqəsidir: alt sinif həm də ana sinfin sinif spesifikasiyasına və ana sinfin variasiyasına cavab verir. alt sinif) öz anasını genişləndirir. Bir obyektin digərini genişləndirib-genişləndirmədiyini bilmək istəyirsinizsə, uyğunluq testi edin - IS -A (is).") Buna görə də, HAS-A kompozisiya əlaqəsidir: sinif əksər hallarda bir sıra səbəblərə görə HAS-A prinsipi IS-A-dan daha yaxşı işləyən obyektə sahibdir (və ya ehtiva edir): 
  • Dizayn daha çevikdir;
  • Model daha stabildir, çünki dəyişiklik sinif iyerarxiyası vasitəsilə yayılmır;
  • Bir sinif və onun tərkibi bir valideyn və onun alt sinfini sıx birləşdirən kompozisiya ilə müqayisədə sərbəst şəkildə bağlıdır.
  • Bir sinifdə məntiqi düşüncə qatarı daha sadədir, çünki onun bütün asılılıqları bir yerdə daxil edilir. 
Nə olursa olsun, miras öz yeri var və bir sıra mövcud dizayn problemlərini müxtəlif yollarla həll edir, buna görə də laqeyd yanaşmaq olmaz. Obyekt yönümlü modelinizi tərtib edərkən bu iki alternativi nəzərə alın.

12. KAPSULYASİYA.

Obyekt yönümlü proqramlaşdırmada inkapsulyasiya konsepsiyası bütün icra detallarını (məsələn, iş rejimi, daxili üsullar və s.) xarici dünyadan gizlətməkdir. İnkapsulyasiyanın üstünlükləri davamlılıq və dəyişdirmə asanlığıdır. Sinfin daxili tətbiqi gizlidir, sinif məlumatları ilə işləmək yalnız sinfin ictimai metodları vasitəsilə baş verir (bir çox insanın istifadə etdiyi bir kitabxana və ya çərçivə hazırlayırsanız, əsl problem). Java-da inkapsulyasiya görünmə və əlçatanlıq qaydaları vasitəsilə əldə edilir. Java-da sahələri heç vaxt birbaşa, yalnız alıcılar və tənzimləyicilər vasitəsilə ifşa etmək ən yaxşı təcrübə hesab olunur (sahələr yekun olaraq qeyd olunmayıbsa). Misal üçün:
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;
    }
}
Bu nümunə Java dilində JavaBeans adlanan şeyi xatırladır : standart Java sinifləri bir sıra konvensiyalara uyğun olaraq yazılır, bunlardan biri sahələrə yalnız getter və setter metodlarından istifadə etməklə daxil olmağa imkan verir. Vərəsəlik bölməsində artıq vurğuladığımız kimi, inkapsulyasiya prinsiplərindən istifadə edərək, həmişə sinifdə minimum reklam müqaviləsinə əməl edin. İctimai olmamalı olan hər şey şəxsi (və ya həll etdiyiniz problemdən asılı olaraq qorunan/paket özəl) olmalıdır. Bu, dəyişikliklər etmədən (və ya ən azı onları minimuma endirmədən) dizayn azadlığı verməklə uzun müddətdə öz bəhrəsini verəcəkdir. 

13. YEKUN DƏRSLƏR VƏ METODLAR

Java-da bir sinfin başqa bir sinfin alt sinfinə çevrilməsinin qarşısını almağın bir yolu var: digər sinif final elan edilməlidir. 
package com.javacodegeeks.advanced.design;

public final class FinalClass {
}
Metod elanında  eyni son açar söz alt siniflərin metodu ləğv etməsinə mane olur.
package com.javacodegeeks.advanced.design;

public class FinalMethod {
    public final void performAction() {
    }
}
Bir sinfin və ya metodların yekun olub-olmamasına qərar vermək üçün ümumi qaydalar yoxdur. Yekun siniflər və metodlar genişlənmə qabiliyyətini məhdudlaşdırır və bir sinfin miras alınmalı olub-olmaması və ya metodun gələcəkdə ləğv edilməli olub-olmaması barədə əvvəlcədən düşünmək çox çətindir. Bu, kitabxana tərtibatçıları üçün xüsusilə vacibdir, çünki bu kimi dizayn qərarları kitabxananın tətbiqini əhəmiyyətli dərəcədə məhdudlaşdıra bilər. Java Standart Kitabxanasında son siniflərin bir neçə nümunəsi var, ən məşhuru String sinfidir. Erkən mərhələdə, bu qərar tərtibatçıların sətir tətbiq etmək üçün öz, "daha yaxşı" həllini tapmaq cəhdlərinin qarşısını almaq üçün qəbul edildi. 

14. SONRAKİ NƏ VAR

Dərsin bu hissəsində biz Java-da obyekt yönümlü proqramlaşdırma anlayışlarını əhatə etdik. Biz həmçinin müqavilə proqramlaşdırmasına qısa nəzər saldıq, bəzi funksional anlayışlara toxunduq və dilin zamanla necə inkişaf etdiyini gördük. Dərsin növbəti hissəsində biz generiklərlə və onların proqramlaşdırmada tip təhlükəsizliyinə yanaşma tərzimizi necə dəyişdirdiyi ilə tanış olacağıq. 

15. MƏNBƏ KODU YÜKLƏ

Mənbəni buradan yükləyə bilərsiniz - advanced-java-part-3 Mənbə: Dərsləri necə tərtib etmək olar
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION