Ооп. часть 5. наследование и ещё немного полиморфизма

Параметры со значениями по умолчанию у родительского класса

Рассмотрим случай, когда родительский класс имеет параметры со значениями по умолчанию, а дочерний – нет:

class Table:
    def __init__(self, l=1, w=1, h=1):
        self.length = l
        self.width = w
        self.height = h
 
 
class KitchenTable(Table):
    def __init__(self, p, l, w, h):
        Table.__init__(self, l, w, h)
        self.places = p

При таком определении классов можно создать экземпляр от Table без передачи аргументов для конструктора:

t = Table()

Можем ли мы создать экземпляр от KitchenTable, передав значение только для параметра ? Например, вот так:

k = KitchenTable(10)

Возможно ли, что будет присвоено число 10, а , и получат по единице от родительского класса? Невозможно, будет выброшено исключение по причине несоответствия количества переданных аргументов количеству требуемых конструктором:

...
    k = KitchenTable(10)
TypeError: __init__() missing 3 required
 positional arguments: 'l', 'w', and 'h'

Когда создается объект от дочернего класса, сначала вызывается его конструктор, если он есть. Интерпретатор еще не знает, что в теле этого конструктора будет вызван конструктор родительского класса. Ведь это не обязательно. Значит, если все параметры дочернего конструктора не имеют значений по умолчанию, при построении объекта все значения должны передаваться.

Поэтому, если требуется допустить создание объектов от дочернего класса без передачи аргументов, придется назначить значения по умолчанию также в конструкторе дочернего класса.

class Table:
    def __init__(self, l=1, w=1, h=1):
        self.length = l
        self.width = w
        self.height = h
 
 
class KitchenTable(Table):
    def __init__(self, l=1, w=1, h=0.7, p=4):
        Table.__init__(self, l, w, h)
        self.places = p

Параметр , которого нет у родительского класса, мы делаем последним не просто так. Бывает, объекты разных родственных классов создаются или обрабатываются в одном цикле, то есть по одному алгоритму. При этом у них должны быть одинаковые «интерфейсы», то есть одинаковое количество передаваемых в конструктор аргументов.

Поэтому лучше, когда методы родственных классов принимают одинаковое число параметров. А если разное, то у «лишних» должны быть значения по-умолчанию, чтобы при вызове конструктора их можно было бы не передавать. Если такие параметры находятся еще и в конце, передачу аргументов для предстоящих параметров можно выполнять без ключей.

Другой вариант – отказаться от конструктора в дочернем классе, а значение для поля places устанавливать отдельным вызовом метода:

class Table:
    def __init__(self, l=1, w=1, h=1):
        self.length = l
        self.width = w
        self.height = h
 
 
class KitchenTable(Table):
    places = 4
 
    def set_places(self, p):
        self.places = p

Здесь у всех кухонных столов по-умолчанию будет 4 места. Если мы хотим изменить значение поля places, можем вызвать метод set_places(). Хотя в случае Python можем сделать это напрямую, присвоив полю. При этом у экземпляра появится собственное поле places.

k = KitchenTable()
k.places = 6

Поэтому метод set_places() в общем-то не нужен.

В любом случае произвольное количество мест будет устанавливаться не в конструкторе, а отдельно. Если все же требуется указывать места при создании объекта, это можно сделать и в конструкторе родителя:

class Table:
    def __init__(self, l=1, w=1, h=1):
        self.length = l
        self.width = w
        self.height = h
        if isinstance(self, KitchenTable):
            p = int(input("Сколько мест: "))
            self.places = p

С помощью функции isinstance() проверяется, что создаваемый объект имеет тип KitchenTable. Если это так, то у него появляется поле places.

Мы не используем параметр со значением по умолчанию в заголовке конструктора потому, что, если объектам других родственных классов он не нужен, не происходило путаницы и сложностей с документированием кода.

Абстракция данных в Python

Абстракция – важный аспект объектно-ориентированного программирования. В python мы также можем выполнять скрытие данных, добавляя двойное подчеркивание (___) в качестве префикса к атрибуту, который необходимо скрыть. После этого атрибут не будет виден за пределами класса через объект.

Рассмотрим следующий пример:

 
class Employee: 
    __count = 0; 
    def __init__(self): 
        Employee.__count = Employee.__count+1 
    def display(self): 
        print("The number of employees",Employee.__count) 
emp = Employee() 
emp2 = Employee() 
try: 
    print(emp.__count) 
finally: 
    emp.display() 

Выход:

The number of employees 2 
AttributeError: 'Employee' object has no attribute '__count' 

Изучаю Python вместе с вами, читаю, собираю и записываю информацию опытных программистов.

Типы

Одиночное наследование

Множественное наследование

Существуют различные типы наследования, основанные на парадигме и конкретном языке.

Одиночное наследование
где подклассы наследуют свойства одного суперкласса. Один класс приобретает свойства другого класса.
Множественное наследование
где один класс может иметь более одного суперкласса и наследовать функции от всех родительских классов.
Многоуровневое наследование
где подкласс наследуется от другого подкласса. Нередко класс является производным от другого производного класса, как показано на рисунке «Многоуровневое наследование».

Многоуровневое наследование

Класс служит в качестве базового класса для производного класса B , который в свою очередь служит в качестве базового класса для производного класса C . Класс B известен как промежуточный базовый класс , поскольку он обеспечивает связь для наследования между A и C . Цепочка ABC известна как путь наследования .
Производный класс с многоуровневым наследованием объявляется следующим образом:
Class A(...);      // Base class
Class B  public A(...);   // B derived from A
Class C  public B(...);   // C derived from B
Этот процесс можно расширить до любого количества уровней.
Иерархическое наследование
Здесь один класс служит суперклассом (базовым классом) для более чем одного подкласса. Например, родительский класс A может иметь два подкласса B и C. Родительский класс B и C — это A, но B и C — это два отдельных подкласса.
Гибридное наследование
Гибридное наследование — это когда происходит сочетание двух или более из вышеперечисленных типов наследования. Примером этого является случай, когда класс A имеет подкласс B, который имеет два подкласса, C и D. Это смесь как многоуровневого, так и иерархического наследования.

Использование ключевого слова super

Если ваш метод переопределяет метод базового класса, то вы не можете вызвать метод базового класса напрямую по имени. Вам нужно использовать ключевое слово
super .

Если ваш класс определяет поле с тем же именем, что и поле в родительском классе,пусть даже с другим типом, то это поле скрывает (hide) поле родительского класса. В этом случае вы не можете напрямую обратиться к полю родительского класса по имени. Если всё же нужно обратиться к этому полю родительского класса, то нужно использовать ключевое слово
super .

Пример:

Main.java

Java

class Monster {
double gold = 10.0;

void walk() {
System.out.println(«Monster walk.»);
}
}

class Goblin extends Monster {
// Это скрывает поле gold класса Monster.
double gold = 20.0;

// Это переопределяет метод walk класса Monster.
void walk() {
System.out.println(«Goblin walk»);

System.out.println(«Goblin gold = » + gold);

// Мы можем обратиться к скрытому полю
// родительского класса
System.out.println(«Monster gold = » + super.gold);

// Мы можем вызвать переопределённый метод родительского класса.
super.walk();
}
}

class Main {
public
static void main(String[] args) {
Goblin goblin = new Goblin();
goblin.walk();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

classMonster{

doublegold=10.0;

voidwalk(){

System.out.println(«Monster walk.»);

}

}
 

classGoblinextendsMonster{

// Это скрывает поле gold класса Monster.

doublegold=20.0;

// Это переопределяет метод walk класса Monster.

voidwalk(){

System.out.println(«Goblin walk»);

System.out.println(«Goblin gold = «+gold);

// Мы можем обратиться к скрытому полю

// родительского класса

System.out.println(«Monster gold = «+super.gold);

// Мы можем вызвать переопределённый метод родительского класса.

super.walk();

}

}
 

classMain{

publicstaticvoidmain(Stringargs){

Goblin goblin=newGoblin();

goblin.walk();

}

}

Результат в консоли:

Goblin walk
Goblin gold = 20.0
Monster gold = 10.0
Monster walk.

1
2
3
4

Goblin walk
Goblin gold = 20.0
Monster gold = 10.0
Monster walk.

С помощью ключевого слова
super  можно вызвать конструктор родительского класса в классе потомке:

Main.java

Java

class Monster {
private int ammo;
private double gold;
private double health;

Monster(int ammo, double gold, double health) {
this.ammo = ammo;
this.gold = gold;
this.health = health;
}

}

class Goblin extends Monster {
private int trunks;

Goblin(int ammo, double gold, double health, int trunks) {
super(ammo, gold, health);
this.trunks = trunks;
// …
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

classMonster{

privateintammo;

privatedoublegold;

privatedoublehealth;

Monster(intammo,doublegold,doublehealth){

this.ammo=ammo;

this.gold=gold;

this.health=health;

}

 
}
 

classGoblinextendsMonster{

privateinttrunks;

Goblin(intammo,doublegold,doublehealth,inttrunks){

super(ammo,gold,health);

this.trunks=trunks;

// …

}

}

Вызов конструктора суперкласса должен быть первой инструкцией в конструкторе дочернего класса. Можно вызвать конструктор суперкласса без параметров (конструктор по умолчанию):

Java

super()

1 super()

Если вы не вставили ни одного явного вызова конструктора родительского класса, то компилятор Java автоматически добавит вызов конструктора родительского класса без параметров (конструктора по умолчанию). Если конструктор родительского класса без параметров недоступен из-за модификатора доступа, или конструктора без параметров нет в родительском классе, то возникнет ошибка компиляции.

При создании экземпляра любого объекта происходит цепочка вызовов конструкторов от конструктора создаваемого объекта до конструктора класса
Object . Это называется цепочкой вызова конструкторов (constructor chaining).

Приложения

Наследование используется для соотнесения двух или более классов друг с другом.

Переопределение

Иллюстрация переопределения метода

Многие объектно-ориентированные языки программирования позволяют классу или объекту заменять реализацию аспекта — обычно поведения, — которое он унаследовал. Этот процесс называется переопределением . При переопределении возникает сложность: какую версию поведения использует экземпляр унаследованного класса — ту, которая является частью его собственного класса, или версию родительского (базового) класса? Ответ зависит от языка программирования, и некоторые языки предоставляют возможность указать, что конкретное поведение не должно быть отменено и должно вести себя так, как определено базовым классом. Например, в C # базовый метод или свойство можно переопределить в подклассе, только если он помечен модификатором virtual, abstract или override, тогда как в языках программирования, таких как Java, можно вызывать разные методы для переопределения других методов. Альтернативой переопределению является скрытие унаследованного кода.

Повторное использование кода

Наследование реализации — это механизм, посредством которого подкласс повторно использует код базового класса. По умолчанию подкласс сохраняет все операции базового класса, но подкласс может переопределить некоторые или все операции, заменяя реализацию базового класса своей собственной.

В следующем примере Python подклассы SquareSumComputer и CubeSumComputer переопределяют метод transform () базового класса SumComputer . Базовый класс включает операции по вычислению суммы квадратов между двумя целыми числами. Подкласс повторно использует все функции базового класса, за исключением операции, которая преобразует число в его квадрат, заменяя его операцией, которая преобразует число в его квадрат и куб соответственно. Следовательно, подклассы вычисляют сумму квадратов / кубиков между двумя целыми числами.

Ниже приведен пример Python.

class SumComputer
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def transform(self, x):
        raise NotImplementedError

    def inputs(self):
        return range(self.a, self.b)

    def compute(self):
        return sum(self.transform(value) for value in self.inputs())

class SquareSumComputer(SumComputer):
    def transform(self, x):
        return x * x

class CubeSumComputer(SumComputer):
    def transform(self, x):
        return x * x * x

В большинстве случаев наследование классов с единственной целью повторного использования кода вышло из моды. Основная проблема заключается в том, что наследование реализации не обеспечивает никакой гарантии полиморфной заменяемости — экземпляр класса повторного использования не может обязательно быть заменен экземпляром унаследованного класса. Альтернативный метод, явное делегирование , требует дополнительных усилий по программированию, но позволяет избежать проблемы заменяемости. В C ++ частное наследование может использоваться как форма наследования реализации без возможности замены. В то время как публичное наследование представляет собой отношение «есть-а», а делегирование представляет собой отношение «имеет-а», частное (и защищенное) наследование можно рассматривать как отношение «реализовано в терминах».

Еще одно частое использование наследования — гарантировать, что классы поддерживают определенный общий интерфейс; то есть они реализуют одни и те же методы. Родительский класс может быть комбинацией реализованных операций и операций, которые должны быть реализованы в дочерних классах. Часто между супертипом и подтипом не происходит изменения интерфейса — дочерний класс реализует описанное поведение вместо своего родительского класса.

10. Class вместо function

В js поддерживается такая языковая конструкция как класс. Перепишем наш пример с их использованием.

Реализация классов с помощью конструкции оставляет за бортом возню с прототипами

Не будем заостряться на синтаксисе, ибо он не из ряда вон выходящий, но обратим внимание на то, что прототипная архитектура функций осталась прежней. Сам класс при этом остаётся по сути и за исключением каких-то нюансов той же функцией

Заметим, что прототип производного класса равен базовому: . При использовании конструкции такая связь устанавливалась через метод . Эта связь позволяет производному классу вызывать статические методы базового класса.

Классовое наследование

Классовое наследование в JavaScript можно рассматривать как функциональное наследование с расширенными возможностями: создание класса с использованием ключевого слова class фактически является формой функции-конструктора, поэтому классовое наследование может как использовать ключевое слово class из ES6, так и не использовать его (функциональное наследование через функции-конструкторы).

Особенности классового наследования:

  1. для создания дочернего класса в объявлении класса (или в выражениях класса) применяется ключевое слово extends, использующее прототипы (prototype);
  2. для вызова функций, принадлежащих родителю объекта, используется ключевое слово super.

Ключевое слово extends позволяет наследовать методы родительского класса, вынесенные в prototype:

// Класс Person содержит только свойства
class Person {
constructor(first, last, age, gender) {
this.name = { first, last };
this.age = age;
}
}

//  Методы класса Person вынесены в прототип
Person.prototype.greeting = function () {
return «Hi! I’m » + this.name.first + «.»;
};

// Создадим наследник класса Person
class Teacher extends Person {}

let teacher = new Teacher(«Serg»,’VAN’);
console.log(teacher); // Teacher {name: {first: «Serg», last: «VAN»}, age: undefined}
console.log(teacher.__proto__); // Person {constructor: ƒ}
console.log(teacher.greeting()); // Hi! I’m Serg. (метод родительского класса доступен)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

// Класс Person содержит только свойства

classPerson{

constructor(first,last,age,gender){

this.name={first,last};

this.age=age;

}

}
 
//  Методы класса Person вынесены в прототип

Person.prototype.greeting=function(){

return»Hi! I’m «+this.name.first+».»;

};

 
// Создадим наследник класса Person

classTeacherextendsPerson{}

let teacher=newTeacher(«Serg»,’VAN’);

console.log(teacher);// Teacher {name: {first: «Serg», last: «VAN»}, age: undefined}

console.log(teacher.__proto__);// Person {constructor: ƒ}

console.log(teacher.greeting());// Hi! I’m Serg. (метод родительского класса доступен)

Ключевое слово super используется для вызова функций, принадлежащих родителю объекта. В конструкторе ключевое слово super() используется как функция, вызывающая родительский конструктор: её необходимо вызвать до первого обращения к ключевому слову this в теле конструктора:

class Polygon {
constructor(height, width) {
this.name = «Polygon»;
this.height = height;
this.width = width;
}
}

class Square extends Polygon { // ключевое слово extends использовано для создания дочернего класса
constructor(height, width) {
// this.height; // ReferenceError, super должен быть вызван первым
super(height, width); // Вызов метода конструктора родительского класса с длинами, указанными для ширины и высоты класса Polygon
this.name = «Square»;
}
get area() {
return this.height * this.width;
}
}

let s = new Square(300,200);
console.log(s); // Square {name: «Square», height: 300, width: 200}
console.log(s.area); // 60000

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

classPolygon{

constructor(height,width){

this.name=»Polygon»;

this.height=height;

this.width=width;

}

}

classSquareextendsPolygon{// ключевое слово extends использовано для создания дочернего класса

constructor(height,width){

//  this.height; // ReferenceError, super должен быть вызван первым

super(height,width);// Вызов метода конструктора родительского класса с длинами, указанными для ширины и высоты класса Polygon

this.name=»Square»;

}

get area(){

returnthis.height *this.width;

}

}

lets=newSquare(300,200);

console.log(s);// Square {name: «Square», height: 300, width: 200}

console.log(s.area);// 60000

Наследование

Наследование — это механизм объектно ориентированного программирования, который позволяет описать новый класс на основе уже существующего (родительского).

Класс, который получается в результате наследования от другого, называется подклассом. Эту связь обычно описывают с помощью терминов «родительский» и «дочерний». Дочерний класс происходит от родительского и наследует его характеристики: свойства и методы. Обычно в подклассе к функциональности родительского класса (который также называют суперклассом) добавляются новые функциональные возможности.

Чтобы создать подкласс, необходимо использовать в объявлении класса ключевое слово , и после него указать имя класса, от которого выполняется наследование:

<?php
  
  class Cat {
    public $age;
	
	function __construct($age) {
	  $this->age = $age;
	}
	
	function add_age () {
	  $this->age++;
	}
  
  }
  
  // объявляем наследуемый класс
  class my_Cat extends Cat {
    // определяем собственный метод подкласса
    function sleep() {
	  echo '<br>Zzzzz...';
	}
  }

  $kitty = new my_Cat(10);
  
  // вызываем наследуемый метод
  $kitty->add_age();
  
  // считываем значение наследуемого свойства
  echo $kitty->age;
  
  // вызываем собственный метод подкласса
  $kitty->sleep();
  
?>

Подкласс наследует доступ ко всем методам и свойствам родительского класса, так как они имеют тип . Это означает, что для экземпляров класса мы можем вызывать метод и обращаться к свойству не смотря на то, что они определены в классе . Также в приведенном примере подкласс не имеет своего конструктора. Если в подклассе не объявлен свой конструктор, то при создании экземпляров подкласса будет автоматически вызываться конструктор суперкласса.

Обратите внимание на то, что в подклассах могут переопределяться свойства и методы. Определяя подкласс, мы гарантируем, что его экземпляр определяется характеристиками сначала дочернего, а затем родительского класса

Чтобы лучше это понять рассмотрим пример:

<?php
  
  class Cat {
	public $age = 5;
	
	function foo() {
	  echo "$this->age";
	}
  }
  
  class my_Cat extends Cat {
    public $age = 10;
  }
  
  $kitty = new my_Cat;
  
  $kitty->foo();
  
?>

При вызове интерпретатор PHP не может найти такой метод в классе , поэтому используется реализация этого метода заданная в классе . Однако в подклассе определено собственное свойство , поэтому при обращении к нему в методе , интерпретатор PHP находит это свойство в классе и использует его.

Так как мы уже рассмотрели тему про указание типа аргументов, осталось сказать о том, что если в качестве типа указан родительский класс, то все потомки для метода будут так же доступны для использования, посмотрите на следующий пример:

<?php
  
  class Cat {
    function foo(Cat $obj) {}
  }
   
  class my_Cat extends Cat {}
   
  $kitty = new Cat;
  
  // передаем методу экземпляр класса my_Cat  
  $kitty->foo( new my_Cat );
  
?>

Мы можем обращаться с экземпляром класса так, как будто это объект типа , т.е. мы можем передать объект типа методу класса , и все будет работать, как надо.

Практическая работа

Разработайте программу по следующему описанию.

В некой игре-стратегии есть солдаты и герои. У всех есть свойство, содержащее уникальный номер объекта, и свойство, в котором хранится принадлежность команде. У солдат есть метод «иду за героем», который в качестве аргумента принимает объект типа «герой». У героев есть метод увеличения собственного уровня.

В основной ветке программы создается по одному герою для каждой команды. В цикле генерируются объекты-солдаты. Их принадлежность команде определяется случайно. Солдаты разных команд добавляются в разные списки.

Измеряется длина списков солдат противоборствующих команд и выводится на экран. У героя, принадлежащего команде с более длинным списком, увеличивается уровень.

Отправьте одного из солдат первого героя следовать за ним. Выведите на экран идентификационные номера этих двух юнитов.

Особенности наследования

Есть несколько особенностей, которые нужно знать при работе с наследованием:

  1. Наследовать можно только от класса, уровень доступа которого выше дочернего или равен ему. То есть публичный класс не может наследоваться от приватного.
  2. Дочерний класс не может обращаться к приватным полям и методам родительского. Поэтому нужно либо определять логику приватных компонентов в базовом классе, либо создавать публичные свойства и методы, которые будут своего рода посредниками.
  3. У дочернего класса может быть только один родительский, но у родительского может быть несколько дочерних.
  4. Нельзя наследовать от класса с модификатором static.
  5. Можно наследовать от класса, который наследует от другого класса. Но с этим лучше не злоупотреблять, потому что можно быстро запутаться в их взаимосвязях.

Что такое наследование в php

В этом разделе помещены уроки по PHP скриптам, которые Вы сможете использовать на своих ресурсах.

Фильтрация данных с помощью zend-filter

Когда речь идёт о безопасности веб-сайта, то фраза «фильтруйте всё, экранируйте всё» всегда будет актуальна. Сегодня поговорим о фильтрации данных.

Контекстное экранирование с помощью zend-escaper

Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак

В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода

Подключение Zend модулей к Expressive

Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.

Совет: отправка информации в Google Analytics через API

Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.

Подборка PHP песочниц

Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.

Совет: активация отображения всех ошибок в PHP

При поднятии PHP проекта на новом рабочем окружении могут возникнуть ошибки отображение которых изначально скрыто базовыми настройками. Это можно исправить, прописав несколько команд.

Открытое наследование

Открытое наследование – это, безусловно, наиболее часто используемый тип наследования

Фактически, вы очень редко увидите или будете использовать другие типы наследования, поэтому ваше основное внимание должно быть сосредоточено на понимании этого раздела. К счастью, открытое наследование также легче всего для понимания

Когда вы наследуете базовый класс открыто, унаследованные открытые члены остаются открытыми, а унаследованные защищенные члены остаются защищенными. Унаследованные закрытые члены, которые были недоступны, потому что они были закрытыми в базовом классе, остаются недоступными.

Спецификатор доступа в базовом классе Спецификатор доступа при открытом наследовании
не доступен

Ниже приведен пример, показывающий, как всё работает:

Это то же самое, что и в приведенном выше примере, где мы ввели спецификатор защищенного доступа, за исключением того, что мы также создали экземпляр производного класса, просто чтобы показать, что с открытым наследованием в базовом и производном классах всё работает одинаково.

Если у вас нет особой причины делать иначе, то вы должны использовать открытое наследование.

Лучшая практика

Используйте открытое наследование, если у вас нет особых причин делать иначе.

Ассоциация

Ассоциация, как следует из название, это способ взаимодействия, когда один класс ассоциируется с другим. Т.е. один класс использует внутри своей реализации свойства или методы объекта другого класса. Просто запомните, что в отличии от наследования, ассоциации не РАСШИРЯЮТ класс, а ИСПОЛЬЗУЮТ объект другого класса. Дальше мы это увидим на примерах, а пока надо упомянуть, что ассоциации бывают двух видов: Композиция и Агрегация.

Композиция

Это ассоциация, при которой используемый объект создается внутри класса. Простой пример:

<?php

class A {
public function helloWorld(){
echo ‘Hello World’;
}
}

class B {
protected $a;
public function __construct(){
$this->a = new A; // создает объект другого класса
}
public function sayHello(){
$this->a->helloWorld(); // использует объект другого класса
}
}

$obj = new B;
$obj->sayHello();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

<?php

classA{

publicfunctionhelloWorld(){

echo’Hello World’;

}

}
 

classB{

protected$a;

publicfunction__construct(){

$this->a=newA;// создает объект другого класса

}

publicfunctionsayHello(){

$this->a->helloWorld();// использует объект другого класса

}

}
 

$obj=newB;

$obj->sayHello();

 

Тут мы видим, что в конструкторе класса B, создается объект класса A. И дальше используется в методе sayHello.

Композиция — это по сути включение класса, внутрь другого класса с помощью создания объекта внутри этого класса.

У такого подхода есть один огромный недостаток — сильная связанность, это значит, что для того чтобы поменять класс A на A1 вам придется переписывать конструктор (new A1 вместо A).

Преимущество у такого способа, это то, что класс B, управляет временем жизни объекта A. Т.е. при удалении объекта B будет и удален, объект A который был создан внутри B.

Агрегация

Это ассоциация, при которой используемый объект создается вне класса. Простой пример:

<?php

class A {
public function helloWorld(){
echo ‘Hello World’;
}
}

class B {
protected $a;
public function __construct(A $a){
$this->a = $a;
}
public function sayHello(){
$this->a->helloWorld(); // использует объект другого класса
}
}

$objA = new A; // создает объект другого класса

$objB = new B($objA);
$objB->sayHello();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

<?php

classA{

publicfunctionhelloWorld(){

echo’Hello World’;

}

}
 

classB{

protected$a;

publicfunction__construct(A$a){

$this->a=$a;

}

publicfunctionsayHello(){

$this->a->helloWorld();// использует объект другого класса

}

}
 

$objA=newA;// создает объект другого класса

$objB=newB($objA);

$objB->sayHello();

 

Тут мы видим, что создается объект класса A, а заетм он передается извне в конструктор класса B. И дальше используется в методе sayHello.

Агрегация — это по сути включение класса, внутрь другого класса с помощью передачи объекта внутрь этого класса.

В отличие от композиции, тут все наоборот. Преимущество: легко передать новый объект A1 без изменений в коде — слабая связанность. Из недостатков, пожалуй, следует отметить, что в больших системах это приводит к огромному кол-ву переменных в конструкторе (хороший пример этой проблемы , к счастью сейчас это уже убрали).

5 последних уроков рубрики «PHP»

Когда речь идёт о безопасности веб-сайта, то фраза «фильтруйте всё, экранируйте всё» всегда будет актуальна. Сегодня поговорим о фильтрации данных.

Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак

В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.

Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение

В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.

Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.

Подборка PHP песочниц
Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.

Рейтинг
( Пока оценок нет )
Editor
Editor/ автор статьи

Давно интересуюсь темой. Мне нравится писать о том, в чём разбираюсь.

Понравилась статья? Поделиться с друзьями:
Люкс-хост
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: