9.1 Совместная работа интерфейсов и классов
Интерфейсы позволяют описывать контракты, которым должны соответствовать объекты, а классы обеспечивают реализацию этих контрактов. Совместное использование интерфейсов и классов позволяет создать гибкий и поддерживаемый код, который легко расширять и модифицировать.
В этой лекции мы разберем и закрепим, как интерфейсы и классы работают вместе, как их можно использовать для определения типов и реализации функциональности, а также рассмотрим примеры использования.
Интерфейсы
Интерфейсы в TypeScript используются для определения контрактов, которые должны соблюдать объекты. Они описывают структуру объектов, определяя набор свойств и методов, которые должны быть у объекта.
Пример:
"use strict";
let person = {
name: 'Alice',
age: 30,
greet() {
console.log(`Hello, my name is ${this.name}.`);
}
};
person.greet(); // Вывод: Hello, my name is Alice.
interface Person {
name: string;
age: number;
greet(): void;
}
let person: Person = {
name: 'Alice',
age: 30,
greet() {
console.log(`Hello, my name is ${this.name}.`);
}
};
person.greet(); // Вывод: Hello, my name is Alice.
Классы
Классы в TypeScript представляют собой шаблоны для создания объектов. Они могут реализовывать интерфейсы, что обеспечивает соблюдение определенных контрактов и упрощает реализацию полиморфизма.
Пример:
"use strict";
class Employee {
constructor(name, age, position) {
this.name = name;
this.age = age;
this.position = position;
}
greet() {
console.log(`Hello, my name is ${this.name} and I am a ${this.position}.`);
}
}
let employee = new Employee('Bob', 40, 'Manager');
employee.greet(); // Вывод: Hello, my name is Bob and I am a Manager.
interface Person {
name: string;
age: number;
greet(): void;
}
class Employee implements Person {
name: string;
age: number;
position: string;
constructor(name: string, age: number, position: string) {
this.name = name;
this.age = age;
this.position = position;
}
greet(): void {
console.log(`Hello, my name is ${this.name} and I am a ${this.position}.`);
}
}
let employee = new Employee('Bob', 40, 'Manager');
employee.greet(); // Вывод: Hello, my name is Bob and I am a Manager.
В этом примере класс Employee реализует интерфейс Person, гарантируя, что все свойства и методы интерфейса будут определены в классе.
9.2 Реализация интерфейсов в классах
Когда класс реализует интерфейс, он должен предоставить реализацию всех свойств и методов, определенных в интерфейсе. Это помогает гарантировать, что класс соответствует определенному контракту.
Пример реализации интерфейсов:
"use strict";
class Dog {
constructor(name) {
this.name = name;
}
makeSound() {
console.log('Woof! Woof!');
}
}
class Cat {
constructor(name) {
this.name = name;
}
makeSound() {
console.log('Meow! Meow!');
}
}
let dog = new Dog('Rex');
dog.makeSound(); // Вывод: Woof! Woof!
let cat = new Cat('Whiskers');
cat.makeSound(); // Вывод: Meow! Meow!
interface Animal {
name: string;
makeSound(): void;
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound(): void {
console.log('Woof! Woof!');
}
}
class Cat implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound(): void {
console.log('Meow! Meow!');
}
}
let dog: Animal = new Dog('Rex');
dog.makeSound(); // Вывод: Woof! Woof!
let cat: Animal = new Cat('Whiskers');
cat.makeSound(); // Вывод: Meow! Meow!
Здесь классы Dog и Cat реализуют интерфейс Animal, что гарантирует наличие свойства name и метода makeSound в обоих классах.
Наследование интерфейсов
Интерфейсы в TypeScript могут наследовать другие интерфейсы, что позволяет создавать сложные типы на основе более простых.
Пример синтаксиса наследования интерфейсов:
"use strict";
let employee = {
name: 'Alice',
age: 30,
position: 'Developer',
salary: 80000
};
console.log(employee);
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
position: string;
salary: number;
}
let employee: Employee = {
name: 'Alice',
age: 30,
position: 'Developer',
salary: 80000
};
console.log(employee);
Здесь интерфейс Employee наследует интерфейс Person, добавляя свойства position и salary.
9.3 Реализация нескольких интерфейсов
Класс в TypeScript может реализовывать несколько интерфейсов, что позволяет комбинировать различные контракты.
Синтаксис реализации нескольких интерфейсов:
"use strict";
class FlyingCar {
drive() {
console.log('Driving on the road...');
}
fly() {
console.log('Flying in the sky...');
}
}
let myFlyingCar = new FlyingCar();
myFlyingCar.drive(); // Вывод: Driving on the road...
myFlyingCar.fly(); // Вывод: Flying in the sky...
interface Drivable {
drive(): void;
}
interface Flyable {
fly(): void;
}
class FlyingCar implements Drivable, Flyable {
drive(): void {
console.log('Driving on the road...');
}
fly(): void {
console.log('Flying in the sky...');
}
}
let myFlyingCar = new FlyingCar();
myFlyingCar.drive(); // Вывод: Driving on the road...
myFlyingCar.fly(); // Вывод: Flying in the sky...
В этом примере класс FlyingCar реализует интерфейсы Drivable и Flyable, что позволяет объекту myFlyingCar ездить и летать.
9.4 Интерфейсы и классы в реальных проектах
Совместное использование интерфейсов и классов позволяет создавать гибкие и легко поддерживаемые архитектуры в реальных проектах. Рассмотрим несколько примеров.
Пример 1: Управление пользователями
"use strict";
class Admin {
constructor(id, name, email, adminLevel) {
this.id = id;
this.name = name;
this.email = email;
this.adminLevel = adminLevel;
}
getDetails() {
return `Admin: ${this.name} (Level ${this.adminLevel})`;
}
}
class Member {
constructor(id, name, email, membershipType) {
this.id = id;
this.name = name;
this.email = email;
this.membershipType = membershipType;
}
getDetails() {
return `Member: ${this.name} (${this.membershipType} Membership)`;
}
}
let admin = new Admin(1, 'Alice', 'alice@example.com', 5);
console.log(admin.getDetails()); // Вывод: Admin: Alice (Level 5)
let member = new Member(2, 'Bob', 'bob@example.com', 'Gold');
console.log(member.getDetails()); // Вывод: Member: Bob (Gold Membership)
interface User {
id: number;
name: string;
email: string;
getDetails(): string;
}
class Admin implements User {
id: number;
name: string;
email: string;
adminLevel: number;
constructor(id: number, name: string, email: string, adminLevel: number) {
this.id = id;
this.name = name;
this.email = email;
this.adminLevel = adminLevel;
}
getDetails(): string {
return `Admin: ${this.name} (Level ${this.adminLevel})`;
}
}
class Member implements User {
id: number;
name: string;
email: string;
membershipType: string;
constructor(id: number, name: string, email: string, membershipType: string) {
this.id = id;
this.name = name;
this.email = email;
this.membershipType = membershipType;
}
getDetails(): string {
return `Member: ${this.name} (${this.membershipType} Membership)`;
}
}
let admin = new Admin(1, 'Alice', 'alice@example.com', 5);
console.log(admin.getDetails()); // Вывод: Admin: Alice (Level 5)
let member = new Member(2, 'Bob', 'bob@example.com', 'Gold');
console.log(member.getDetails()); // Вывод: Member: Bob (Gold Membership)
Здесь классы Admin и Member реализуют интерфейс User, добавляя специфичные для них свойства и методы.
Пример 2: Оплата заказов
"use strict";
class CreditCard {
constructor(cardNumber) {
this.cardNumber = cardNumber;
}
processPayment(amount) {
console.log(`Processing credit card payment of $${amount} using card ${this.cardNumber}.`);
}
}
class PayPal {
constructor(email) {
this.email = email;
}
processPayment(amount) {
console.log(`Processing PayPal payment of $${amount} using email ${this.email}.`);
}
}
let paymentMethod;
paymentMethod = new CreditCard('1234-5678-8765-4321');
paymentMethod.processPayment(100); // Вывод: Processing credit card payment of $100 using card 1234-5678-8765-4321.
paymentMethod = new PayPal('user@example.com');
paymentMethod.processPayment(200); // Вывод: Processing PayPal payment of $200 using email user@example.com.
interface PaymentMethod {
processPayment(amount: number): void;
}
class CreditCard implements PaymentMethod {
cardNumber: string;
constructor(cardNumber: string) {
this.cardNumber = cardNumber;
}
processPayment(amount: number): void {
console.log(`Processing credit card payment of $${amount} using card ${this.cardNumber}.`);
}
}
class PayPal implements PaymentMethod {
email: string;
constructor(email: string) {
this.email = email;
}
processPayment(amount: number): void {
console.log(`Processing PayPal payment of $${amount} using email ${this.email}.`);
}
}
let paymentMethod: PaymentMethod;
paymentMethod = new CreditCard('1234-5678-8765-4321');
paymentMethod.processPayment(100); // Вывод: Processing credit card payment of $100 using card 1234-5678-8765-4321.
paymentMethod = new PayPal('user@example.com');
paymentMethod.processPayment(200); // Вывод: Processing PayPal payment of $200 using email user@example.com.
В этом примере интерфейс PaymentMethod используется для определения контракта, который должны реализовывать различные способы оплаты, такие как CreditCard и PayPal.
Преимущества совместного использования интерфейсов и классов
- Явная типизация: интерфейсы позволяют явно определять структуру объектов, что улучшает читаемость и поддерживаемость кода.
- Полиморфизм: совместное использование интерфейсов и классов упрощает реализацию полиморфизма, позволяя использовать объекты различных классов через общий интерфейс.
- Повторное использование кода: классы могут реализовывать несколько интерфейсов, что позволяет комбинировать различные контракты и уменьшать дублирование кода.
- Гибкость и расширяемость: интерфейсы и классы обеспечивают гибкость в проектировании и расширении приложений, позволяя легко добавлять новые типы объектов и функциональность.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ