Объектіге бағытталған бағдарламалауда әлсіз негізгі класс мәселесі
Fragile base class
Объектілі бағдарламалаудағы әкел сынып мәселесі: тұрақты архитектура үшін негізгі сыныптарды өзгертудің қауіпсіздігі, мұрагерліктегі бұзушылықтар, шешімдері.
Ағылшыншамен салыстырыңыз: абзацты басыңыз — түпнұсқа терезеде ашылады. Абзац астындағы EN түймесі оны мәтін ішінде көрсетеді.
Кіріспе
Нысанға бағытталған бағдарламалау жүйесінің мәселесі – архитектуралық мәселе.
Object oriented programming system problem
the architectural problem
Нысанға бағытталған бағдарламалау жүйелеріндегі маңызды архитектуралық мәселе – бұл «нашар базалық класс» мәселесі. Бұл жағдайда базалық класс (суперкласс) «нашар» болып саналады, себебі базалық классқа енгізілген көріне берілген қауіпсіз өзгерістер, туынды классқа мұрагерлік еткен кезде, туынды кластың жұмысын бұзуы мүмкін. Бағдарламашы базалық кластың әдістерін жеке қарап ғана оның өзгертудің қауіпсіздігін анықтай алмайды. Мүмкін болатын шешімдердің бірі – инстанция айнымалыларын оларды анықтаған классқа жеке қылып, кіші кластарды суперкластың күйін өзгерту үшін тек аксессорларды пайдалануға мәжбүрлеу. Сонымен қатар, тіл кіші кластарға мұрагерлікке алынған әдістердің қайсысын көпшілікке ашуға болатынын бақылау мүмкіндігін беруі мүмкін. Бұл өзгерістер кіші кластардың суперкластың іске асылу егжей-тегжейлеріне сүйенуіне жол бермейді және кіші кластарға тек оларға қатысты суперкластың әдістерін көрсетуге мүмкіндік береді. Балама шешім – суперкластың орнына интерфейс қолдану. «Нашар базалық класс» мәселесі ашық рекурсияға (әдістерді динамикалық шақыру, `this` арқылы) байланысты деп есептеледі. Осыған байланысты, әдістерді шақыру кезінде ашық рекурсияны (динамикалық шақыру, кешіктірілген байланыс) емес, жабық рекурсияны (статикалық шақыру, ерте байланыс) пайдалану ұсынылады, ашық рекурсия тек қана қажет болған жағдайда қолданылуы керек; сыртқы шақырулар (`this` қолданбай) әдеттегідей динамикалық шақырылады.
The fragile base class problem is a fundamental architectural problem of object oriented programming systems where base classes (superclasses) are considered "fragile" because seemingly safe modifications to a base class, when inherited by the derived classes, may cause the derived classes to malfunction. The programmer cannot determine whether a base class change is safe simply by examining in isolation the methods of the base class. One possible solution is to make instance variables private to their defining class and force subclasses to use accessors to modify superclass states. A language could also make it so that subclasses can control which inherited methods are exposed publicly. These changes prevent subclasses from relying on implementation details of superclasses and allow subclasses to expose only those superclass methods that are applicable to themselves. An alternative solution is to have an interface instead of superclass. The fragile base class problem has been blamed on open recursion (dynamic dispatch of methods on this), with the suggestion that invoking methods on this default to closed recursion (static dispatch, early binding) rather than open recursion (dynamic dispatch, late binding), only using open recursion when it is specifically requested; external calls (not using this) would be dynamically dispatched as usual.
Шешімдер
Objective C-де категориялармен қатар, сындырылмайтын экземпляр айнымалылары да бар. Component Pascal суперкласс шақыруларын қолдамайды. Java, C++ (C++11 нұсқасынан бастап) және D кластың әдісін мұраға алу немесе қайта жазу мүмкіндігін кластың немесе әдістің декларациясын "final" кілт сөзімен белгілеп, тыйым салу арқылы шектеуге болады. Effective Java кітабының авторы Джошуа Блох (17-тарауда) бағдарламашылардың "мұраға алуға мүмкіндік беру үшін жобалау және құжаттау керек, әйтпесе оған тыйым салу керек" деп жазады. C# және VB. NET, Java сияқты, мұраға алуға тыйым салу үшін "sealed" және "Not Inheritable" сынып декларация кілт сөздерін пайдаланады және қайта жазылатын әдістерде "override" кілт сөзін қолдануды талап етеді, бұл шешім кейіннен Scala-да қабылданды. Scala кіші сыныптың ата-ана сынып әдісін қайта жазу үшін "override" кілт сөзін міндетті түрде пайдалануын қажет етеді. "Programming in Scala, 2nd Edition" кітабында автор былай деп жазады (өзгерістермен): Егер f әдісі болмаса, клиенттің f әдісінің бастапқы реализациясында қайта жазу модификаторы болмауы мүмкін еді. Кітапхана класының екінші нұсқасына f әдісін қосқаннан кейін, клиенттік кодты қайта компиляциялау дұрыс емес мінез-құлық орнына компиляция қатесін тудырады. Kotlin-де кластар мен әдістер әдепкі бойынша final болып табылады. Кластың мұраға алуын қосу үшін, кластың "open" модификаторымен белгіленуі керек. Сол сияқты, әдістің қайта жазылуын рұқсат ету үшін әдіс "open" деп белгіленуі керек. Julia абстракті типтерді ғана субтиплеуге рұқсат береді және мұрагерлікке балама ретінде композицияны пайдаланады. Дегенмен, оның көптеген жіберу механизмі бар.
Objective C has categories as well as non fragile instance variables. Component Pascal deprecates superclass calls. Java, C++ (Since C++11) and D allow inheritance or overriding a class method to be prohibited by labeling a declaration of a class or method, respectively, with the keyword "final". In the book Effective Java, author Joshua Bloch writes (in item 17) that programmers should "Design and document for inheritance or else prohibit it". C# and VB. NET like Java have "sealed" and "Not Inheritable" class declaration keywords to prohibit inheritance, and require a subclass to use keyword "override" on overriding methods, the same solution later adopted by Scala. Scala require a subclass to use keyword "override" explicitly in order to override a parent class method. In the book "Programming in Scala, 2nd Edition", the author writes that (with modifications here) If there was no method f , the client’s original implementation of method f could not have had an override modifier. Once you add the f method to the second version of your library class, a recompile of the client code would give an compile error instead of wrong behavior. In Kotlin classes and methods are final by default. To enable the class inheritance, the class should be marked with the open modifier. Likewise, a method should be marked as open to allow overriding of the method. Julia allows only subtyping of abstract types and uses composition as an alternative to inheritance. It however has multiple dispatch.