Приклади застосування внутрішніх класів в поєднанні з інтерфейсами. Низхідне та висхідне перетворення. Переваги застосування висхідного перетворення
Зміст
- 1. Суть низхідного перетворення
- 2. Особливості реалізації висхідного перетворення у випадку внутрішнього private-класу
- 3. Переваги застосування висхідного перетворення у поєднанні з внутрішніми класами
- 4. Особливості реалізації висхідного перетворення у випадку внутрішнього protected-класу
- 5. Приклад, що демонструє низхідне перетворення
- 6. Приклад, що демонструє висхідне перетворення
- 7. Яка відмінність між низхідним перетворенням та висхідним перетворенням? Приклад
- Зв’язані теми
Пошук на інших ресурсах:
1. Суть низхідного перетворення
Якщо у класі OutClass оголошується внутрішній клас InClass, який має доступ public
class OutClass { public class InClass { // реалізація класу InClass // ... // реалізація методів класу InClass int method1() { // інструкції методу method1() // ... } int method2() { // інструкції методу method2() // ... } } }
то при низхідному перетворенні використати методи method1(), method2() класу InClass можна за наступною схемою
// демонстрація використання низхідного перетворення // створити об’єкт класу OutClass стандартним способом OutClass oc = new OutClass(); // створити об’єкт класу OutClass.InClass з допомогою інструкції .new OutClass.InClass ic = oc.new OutClass.InClass();
Отже, при низхідному перетворенні важливо, щоб внутрішній клас мав доступ public.
⇑
2. Особливості реалізації висхідного перетворення у випадку внутрішнього private-класу
Якщо потрібно використати переваги висхідного перетворення для внутрішнього класу, то потрібно дотримуватись нижченаведених кроків. Для прикладу розглянуто внутрішній клас, який повинен надати програмісту-клієнту два методи в користування з обмеженим доступом до інших типів та реалізацій внутрішнього класу. Методи мають імена method1(), method2().
Послідовність кроків наступна.
1. Оголосити private-внутрішній клас InClass у зовнішньому класі OutClass
class OutClass { private class InClass { // реалізація класу InClass // ... // реалізація методів, які мають бути доступні програмісту-клієнту int method1() { // інструкції методу method1() // ... } int method2() { // інструкції методу method2() // ... } } }
Після такого оголошення, доступ до внутрішнього private-класу InClass має тільки зовнішній для нього клас OutClass. Програміст-клієнт немає доступу до класу InClass. Також, неможливо здійснити низхідне перетворення до закритого (private) класу InClass шляхом виклику
OutClass oc = new OutClass(); // OutClass.InClass ic = oc.new InClass(); - це є помилка!
2. Оголосити інтерфейс. На цьому кроці потрібно оголосити інтерфейсу та вибрати внутрішні методи, які будуть доступні програмісту-клієнту а також модифікувати оголошення класу InClass. Ці методи реалізуються в класі InClass за наступним зразком
public interface InterfaceInClass { // інтерфейсні методи, які надаються в користування програмісту-клієнту int method1(); int method2(); } class OutClass { // дані та методи класу OutClass // ... // реалізація класу InClass з врахуванням методів інтерфейсу InterfaceInClass // додається 'implements ' private class InClass implements InterfaceInClass { // ... // реалізація інтерфейсних методів int method1() { // ... } int method2() { // ... } } }
У вищенаведеному коді програмісту-клієнту надаються в користування два методи
int method1(); int mehtod2();
Імена методів та їх параметри вибрані навмання.
3. Оголосити метод, що реалізує висхідне перетворення. На третьому етапі у класі OutClass формується метод, який повертає об’єкт класу InClass. Після цих змін, оголошення інтерфейсу InterfaceInClass та класу OutClass буде мати вигляд:
public interface InterfaceInClass { // інтерфейсні методи, які надаються в користування програмісту-клієнту int method1(); int method2(); } class OutClass { // дані та методи класу OutClass // ... // реалізація класу InClass з врахуванням методів інтерфейсу private class InClass implements InterfaceInClass { // ... // реалізація інтерфейсних методів int method1() { // інструкції методу method1() // ... } int method2() { // інструкції методу method2() // ... } } // метод класу OutClass, що повертає об'єкт інтерфейсу InterfaceInClass public InterfaceInClass GetInterfaceInClass() { // деякі інструкції (можуть бути відсутні) // ... return new InClass(); // повернути екземпляр класу InClass } }
Вищенаведена реалізація внутрішнього класу InClass в зовнішньому класі OutClass визначає суть висхідного перетворення. Об’єкт внутрішнього класу отримується за принципом знизу-вверх.
Для вищенаведеного прикладу, програміст-клієнт може використовувати внутрішній клас за наступною схемою
// отримати об’єкт класу OutClass OutClass oc = new OutClass(); // через метод GetInterfaceInClass отримати об'єкт ic InterfaceInClass ic = oc.GetInterfaceInClass(); // викликати метод через отриманий об'єкт ic int res; res = ic.method1();
⇑
3. Переваги застосування висхідного перетворення у поєднанні з внутрішніми класами
Реалізація висхідного перетворення дає розробнику такі переваги:
- забороняється доступ до типів, яким відповідають внутрішні класи;
- приховуються усі деталі реалізації внутрішнього класу;
- програмісту-клієнту надається доступ тільки до необхідних (обмежених) реалізацій внутрішнього класу;
- для програміста-клієнта не буде мати сенсу розширення інтерфейсу за рахунок додавання нових методів, тому що він не буде мати доступ до додаткових методів, що не належать до відкритої частини класу;
- компілятор Java буде мати можливість оптимізувати код.
⇑
4. Особливості реалізації висхідного перетворення у випадку внутрішнього protected-класу
Висхідне перетворення для внутрішніх protected-класів працює за таким самим принципом, як і для внутрішніх private-класів як описано в п.1. У випадку private-класів доступ до внутрішнього класу має зовнішній клас. У випадку protected-класів доступ до внутрішнього класу мають:
- зовнішній клас;
- успадкований від зовнішнього клас;
- класи власного пакету, в якому оголошений зовнішній клас. Специфікатор protected дає доступ в межах власного пакету.
Для protected-класів можна зробити низхідне перетворення тільки з успадкованого класу.
⇑
5. Приклад, що демонструє низхідне перетворення
Оголошується зовнішній клас Calculation, в якому реалізовано множину внутрішніх класів, які проводять математичні обчислення над числами. Один з внутрішніх класів називається Complex. Він реалізує базові операції над комплексними числами. У результаті оголошення клас Calculation має вигляд:
// зовнішній клас, що містить реалізацію класу Complex class Calculation { // внутрішній клас Complex public class Complex { double real; // дійсна частина double imag; // уявна частина // метод, що повертає модуль комплексного числа double Abs() { return Math.sqrt(real*real+imag*imag); } } }
Використання класу Complex в іншому методі демонструє низхідне перетворення
// низхідне перетворення // створити об'єкт класу Complex з допомогою об'єкту класу Calculation Calculation calc = new Calculation(); Calculation.Complex comp = calc.new Complex(); double res; comp.imag = 3; comp.real = 5; // виклик методу обчислення модуля комплексного числа res = comp.Abs(); // res = 5.830951894845301
⇑
6. Приклад, що демонструє висхідне перетворення
Дано клас Calculation, в якому реалізовано прихований (private) внутрішній клас Complex. Клас Complex дає оголошення свого загальнодоступного методу Abs() з допомогою інтерфейсу IComplex.
Реалізація класу Calculation та інтерфейсу IntComplex наступна:
// інтерфейс, що містить сигнатуру методу Abs() interface IntComplex { double Abs(); } // зовнішній клас, який містить внутрішній прихований клас Complex class Calculation { // клас реалізує інтерфейс IntComplex, обробляє комплексні числа private class Complex implements IntComplex { // внутрішні дані класу complex private double imag; // уявна частина комплексного числа private double real; // дійсна частина // конструктор класу з двома параметрами public Complex(double _imag, double _real) { imag = _imag; real = _real; } // реалізація методу, що оголошується в інтерфейсі IntComplex public double Abs() { return Math.sqrt(real*real+imag*imag); } } // повернути об'єкт класу Complex public IntComplex GetComplex(double _imag, double _real) { // повернути об'єкт внутрішнього класу return new Complex(_imag, _real); // виклик конструктора з 2 параметрами } }
Метод GetComplex() класу Calculation повертає об’єкт (екземпляр) внутрішнього класу Complex, реалізуючи тим самим висхідне перетворення. При створенні об’єкту класу Complex в методі GetComplex() викликається конструктор з 2-ма параметрами.
Нижче демонструється використання класу Complex в іншому методі
// висхідне перетворення Calculation calc = new Calculation(); // створити об'єкт зовнішнього класу IntComplex ic = calc.GetComplex(5, 6); // отримати об'єкт внутрішнього класу double res; // викликати метод внутрішнього класу res = ic.Abs(); // res = 7.810249675906654
Через інтерфейс IntComplex() програміст-клієнт має доступ до методів внутрішнього прихованого класу Complex. Доступ здійснюється через об’єкт зовнішнього класу Calculation.
⇑
7. Яка відмінність між низхідним перетворенням та висхідним перетворенням? Приклад
Відмінність між висхідним та низхідним перетворенням проявляється у способі отримання об’єкту внутрішнього класу. При низхідному перетворенні об’єкт внутрішнього класу створюється з допомогою оператора .new шляхом звертання до імені об’єкту зовнішнього класу
// низхідне перетворення OutClass oc = new OutClass(); // створити об'єкт зовнішнього класу OutClass.InClass ic = oc.new InClass(); // створити об'єкт внутрішнього класу
При висхідному перетворенні об’єкт внутрішнього класу отримується з допомогою спеціального методу зовнішнього класу, як показано нижче
OutClass oc = new OutClass();
OutClass.InClass ic = oc.GetObjInClass();
де GetObjInClass() – метод, що створює екземпляр внутрішнього класу OutClass.InClass. У цьому випадку внутрішній клас OutClass.InClass повинен мати доступ public або protected для успадкованого класу.
У випадку реалізації внутрішнього класу у поєднанні з інтерфейсом, програмний код висхідного перетворення може виглядати наступним чином:
OutClass oc = new OutClass();
InterfaceInClass ic = oc.GetInterfaceInClass();
тут
- OutClass – зовнішній клас, для якого створюється об’єкт з іменем oc;
- InterfaceInClass – інтерфейс, що оголошує методи внутрішнього класу для їх використання програмістом-клієнтом;
- GetInterfaceInClass() – метод, що повертає об’єкт (конкретний екземпляр) внутрішнього класу OutClass.InClass(), який реалізує (implements) інтерфейс InterfaceInClass.
⇑
Зв’язані теми
- 1. Вкладені та внутрішні класи. Статичні вкладені класи. Приклади
- 2. Створення об’єктів вкладених статичних та нестатичних класів. Конструкції .this та .new