Концепции ООП: атрибуты, сообщения, вызовы методов, персистентность и интерфейсы
Этот материал дает полный обзор ключевых концепций объектно-ориентированного программирования с примерами атрибутов, сообщений, вызовов методов, персистентности и интерфейсов.
Кратко
Концепции ООП описывают фундаментальные принципы объектно-ориентированного программирования: атрибуты как свойства объектов, сообщения как их взаимодействие, персистентность как хранение данных и интерфейсы как контракты между компонентами.
Определение
Объектно-ориентированное программирование (ООП) использует специальную терминологию для описания концепций и структур.
Атрибут (Attribute/Field/Property)
Атрибут - это свойство или состояние объекта. Он хранит данные, которыми обладает объект.
Характеристики:
- Тип данных: определяет, какого типа данные хранятся (String, int, boolean и т.д.)
- Видимость: public, private, protected, package
- Значение: текущее состояние свойства
- Время жизни: существует столько же, сколько сам объект
Сообщение (Message/Method Call)
Сообщение - это взаимодействие между объектами. Оно заставляет объект выполнить определённое действие.
Составные части:
- Получатель: объект, который получает сообщение
- Селектор: имя вызываемого метода
- Аргументы: параметры метода
- Возвращаемое значение: результат операции
Персистентность (Persistence)
Персистентность - это сохранение данных за пределами времени выполнения программы.
Способы реализации:
- Файловая система: сохранение в файлы
- Базы данных: реляционные или NoSQL
- Облачные хранилища: внешние сервисы хранения
- In-Memory: временное хранение
Интерфейс (Interface/API)
Интерфейс определяет контракт между компонентами и описывает доступные операции.
Типы интерфейсов:
- API программирования: сигнатуры методов
- Web-API: HTTP-endpoints
- Пользовательский интерфейс: компоненты GUI
- Аппаратные интерфейсы: драйверы устройств
Ключевые моменты
- Атрибуты: свойства и данные объектов с контролем видимости
- Сообщения: взаимодействие объектов через вызовы методов
- Вызов методов: выполнение операций над объектами
- Персистентность: долгосрочное сохранение данных
- Интерфейсы: контракты между компонентами, определённые API
- Инкапсуляция: объединение данных и методов в единое целое
- Абстракция: упрощение через скрытие сложности
- Полиморфизм: множественные формы одного интерфейса
Основные элементы
- Атрибуты: свойства данных объектов
- Сообщения: взаимодействие между объектами
- Методы: реализация поведения
- Персистентность: долгосрочное хранение данных
- Интерфейсы: определённые контракты
- Инкапсуляция: объединение данных и методов
- Абстракция: снижение сложности
- Полиморфизм: несколько форм интерфейса
Практические примеры
1. Атрибуты в разных языках
// Java-атрибуты
public class Auto {
// Атрибуты экземпляра (для каждого объекта свои)
private String marke; // Приватное свойство
protected int baujahr; // Защищённое свойство
public double preis; // Открытое свойство
// Атрибут класса (общий для всех объектов)
private static int anzahlAutos = 0;
// Константа
public static final int MAX_GESCHWINDIGKEIT = 250;
// Конструктор для инициализации
public Auto(String marke, int baujahr, double preis) {
this.marke = marke;
this.baujahr = baujahr;
this.preis = preis;
Auto.anzahlAutos++; // Увеличиваем счётчик
}
// Getter и setter для инкапсулированных атрибутов
public String getMarke() {
return marke;
}
public void setMarke(String marke) {
this.marke = marke;
}
public static int getAnzahlAutos() {
return anzahlAutos;
}
}
// C#-атрибуты
public class Mitarbeiter
{
// Автоматические свойства (современный синтаксис)
public string Name { get; set; }
public int Alter { get; private set; } // Только чтение снаружи
// Полное свойство с валидацией
private double gehalt;
public double Gehalt
{
get { return gehalt; }
set
{
if (value >= 0)
gehalt = value;
else
throw new ArgumentException("Gehalt kann nicht negativ sein");
}
}
// Статическое свойство
public static string Firma { get; set; } = "TechCorp";
// Константа
public const decimal MINDESTGEHALT = 2000m;
public Mitarbeiter(string name, int alter, double gehalt)
{
Name = name;
Alter = alter;
Gehalt = gehalt;
}
}
# Python-атрибуты
class Person:
# Атрибут класса
anzahl_personen = 0
def __init__(self, name, alter):
# Атрибуты экземпляра
self.name = name # Открытый
self._alter = alter # Защищённый (по соглашению)
self.__geheim = "data" # Приватный (Name Mangling)
Person.anzahl_personen += 1
# Property для инкапсулированного доступа
@property
def alter(self):
return self._alter
@alter.setter
def alter(self, wert):
if wert >= 0:
self._alter = wert
else:
raise ValueError("Alter kann nicht negativ sein")
# Статический метод
@staticmethod
def get_anzahl_personen():
return Person.anzahl_personen
2. Сообщения и вызовы методов
// Сообщения между объектами
public class Bankkonto {
private double kontostand;
private String kontonummer;
public Bankkonto(String kontonummer, double startbetrag) {
this.kontonummer = kontonummer;
this.kontostand = startbetrag;
}
// Метод для получения сообщений
public void einzahlen(double betrag) {
if (betrag > 0) {
this.kontostand += betrag;
System.out.println("Einzahlung: " + betrag + "€, neuer Kontostand: " + kontostand + "€");
}
}
public boolean abheben(double betrag) {
if (betrag > 0 && kontostand >= betrag) {
kontostand -= betrag;
System.out.println("Abhebung: " + betrag + "€, neuer Kontostand: " + kontostand + "€");
return true;
}
return false;
}
public double getKontostand() {
return kontostand;
}
public String getKontonummer() {
return kontonummer;
}
}
// Клиент отправляет сообщения на счёт
public class Kunde {
private String name;
private Bankkonto konto;
public Kunde(String name, Bankkonto konto) {
this.name = name;
this.konto = konto;
}
// Клиент отправляет сообщения своему счёту
public void geldEinzahlen(double betrag) {
System.out.println(name + " will " + betrag + "€ einzahlen");
konto.einzahlen(betrag); // Отправляем сообщение
}
public boolean geldAbheben(double betrag) {
System.out.println(name + " will " + betrag + "€ abheben");
return konto.abheben(betrag); // Отправляем сообщение
}
public void kontostandPruefen() {
double stand = konto.getKontostand(); // Отправляем сообщение
System.out.println(name + "'s Kontostand: " + stand + "€");
}
}
// Использование сообщений
public class BankingDemo {
public static void main(String[] args) {
Bankkonto konto = new Bankkonto("DE123456789", 1000.0);
Kunde kunde = new Kunde("Max Mustermann", konto);
// Цепь сообщений
kunde.geldEinzahlen(500.0);
kunde.kontostandPruefen();
if (kunde.geldAbheben(200.0)) {
System.out.println("Abhebung erfolgreich");
}
kunde.kontostandPruefen();
}
}
3. Реализация персистентности
// Сериализация для сохранения данных в файл
import java.io.*;
import java.util.*;
public class PersistenzDemo {
// Сериализуемый класс
static class Produkt implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String name;
private double preis;
private transient Date lastModified; // transient = не сериализуется
public Produkt(String id, String name, double preis) {
this.id = id;
this.name = name;
this.preis = preis;
this.lastModified = new Date();
}
// Геттеры и toString
public String getId() { return id; }
public String getName() { return name; }
public double getPreis() { return preis; }
@Override
public String toString() {
return String.format("Produkt[id=%s, name=%s, preis=%.2f]", id, name, preis);
}
}
// Менеджер персистентности
static class PersistenzManager {
private String dateiname;
public PersistenzManager(String dateiname) {
this.dateiname = dateiname;
}
// Сохранение объектов
public void speichereProdukte(List<Produkt> produkte) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(dateiname))) {
oos.writeObject(produkte);
System.out.println("Produkte gespeichert in " + dateiname);
}
}
// Загрузка объектов
@SuppressWarnings("unchecked")
public List<Produkt> ladeProdukte() throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(dateiname))) {
List<Produkt> produkte = (List<Produkt>) ois.readObject();
System.out.println("Produkte geladen aus " + dateiname);
return produkte;
}
}
}
// JSON-персистентность (ручная реализация)
static class JsonPersistenz {
public static void speichereAlsJson(List<Produkt> produkte, String dateiname) throws IOException {
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(dateiname))) {
writer.write("[\n");
for (int i = 0; i < produkte.size(); i++) {
Produkt p = produkte.get(i);
writer.write(String.format(
" {\"id\": \"%s\", \"name\": \"%s\", \"preis\": %.2f}",
p.getId(), p.getName(), p.getPreis()
));
if (i < produkte.size() - 1) {
writer.write(",\n");
}
}
writer.write("\n]");
}
System.out.println("Produkte als JSON gespeichert");
}
}
public static void main(String[] args) {
List<Produkt> produkte = Arrays.asList(
new Produkt("P001", "Laptop", 999.99),
new Produkt("P002", "Maus", 29.99),
new Produkt("P003", "Tastatur", 79.99)
);
PersistenzManager manager = new PersistenzManager("produkte.ser");
try {
// Сериализация
manager.speichereProdukte(produkte);
// Десериализация
List<Produkt> geladeneProdukte = manager.ladeProdukte();
geladeneProdukte.forEach(System.out::println);
// JSON-персистентность
JsonPersistenz.speichereAlsJson(produkte, "produkte.json");
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
4. Интерфейсы и API
// Интерфейс программирования
interface DatenbankSchnittstelle {
// Абстрактные методы (без реализации)
void verbinden() throws DatenbankException;
void trennen();
boolean istVerbunden();
// Методы запросов
List<Map<String, Object>> abfragen(String sql) throws DatenbankException;
int ausfuehren(String sql) throws DatenbankException;
// Default-методы (с Java 8)
default void verbindenMitTimeout(int timeout) throws DatenbankException {
verbinden(); // Стандартная реализация
}
}
// Пользовательский класс исключения
class DatenbankException extends Exception {
public DatenbankException(String nachricht) {
super(nachricht);
}
public DatenbankException(String nachricht, Throwable ursache) {
super(nachricht, ursache);
}
}
// Конкретная реализация
class MySQLDatenbank implements DatenbankSchnittstelle {
private boolean verbunden = false;
private String verbindungsString;
public MySQLDatenbank(String verbindungsString) {
this.verbindungsString = verbindungsString;
}
@Override
public void verbinden() throws DatenbankException {
try {
// Имитация подключения
System.out.println("Verbinde zu MySQL: " + verbindungsString);
Thread.sleep(1000); // Имитируем задержку сети
verbunden = true;
System.out.println("Verbindung hergestellt");
} catch (InterruptedException e) {
throw new DatenbankException("Verbindung unterbrochen", e);
}
}
@Override
public void trennen() {
if (verbunden) {
System.out.println("Verbindung getrennt");
verbunden = false;
}
}
@Override
public boolean istVerbunden() {
return verbunden;
}
@Override
public List<Map<String, Object>> abfragen(String sql) throws DatenbankException {
if (!verbunden) {
throw new DatenbankException("Nicht verbunden");
}
System.out.println("Führe aus: " + sql);
// Имитируемый результат
List<Map<String, Object>> ergebnis = new ArrayList<>();
Map<String, Object> zeile = new HashMap<>();
zeile.put("id", 1);
zeile.put("name", "Testdaten");
ergebnis.add(zeile);
return ergebnis;
}
@Override
public int ausfuehren(String sql) throws DatenbankException {
if (!verbunden) {
throw new DatenbankException("Nicht verbunden");
}
System.out.println("Führe aus: " + sql);
return 1; // Имитируемое количество затронутых строк
}
}
// Использование API
public class ApiDemo {
public static void main(String[] args) {
// Полиморфное использование через интерфейс
DatenbankSchnittstelle db = new MySQLDatenbank("jdbc:mysql://localhost/test");
try {
// Работаем через интерфейс
db.verbinden();
if (db.istVerbunden()) {
List<Map<String, Object>> ergebnis = db.abfragen("SELECT * FROM kunden");
System.out.println("Ergebnis: " + ergebnis.size() + " Zeilen");
int rows = db.ausfuehren("UPDATE kunden SET status = 'active'");
System.out.println("Betroffene Zeilen: " + rows);
}
} catch (DatenbankException e) {
System.err.println("Datenbankfehler: " + e.getMessage());
} finally {
db.trennen();
}
}
}
5. Пример Web-API
// REST API Controller (Spring Boot пример)
@RestController
@RequestMapping("/api/kunden")
public class KundenAPI {
private final KundenService service;
public KundenAPI(KundenService service) {
this.service = service;
}
// GET /api/kunden/{id}
@GetMapping("/{id}")
public ResponseEntity<Kunde> getKunde(@PathVariable Long id) {
try {
Kunde kunde = service.findeKundeById(id);
return ResponseEntity.ok(kunde);
} catch (KundeNotFoundException e) {
return ResponseEntity.notFound().build();
}
}
// POST /api/kunden
@PostMapping
public ResponseEntity<Kunde> createKunde(@RequestBody Kunde kunde) {
Kunde erstellterKunde = service.erstelleKunde(kunde);
return ResponseEntity.status(HttpStatus.CREATED).body(erstellterKunde);
}
// PUT /api/kunden/{id}
@PutMapping("/{id}")
public ResponseEntity<Kunde> updateKunde(@PathVariable Long id, @RequestBody Kunde kunde) {
try {
Kunde aktualisierterKunde = service.aktualisiereKunde(id, kunde);
return ResponseEntity.ok(aktualisierterKunde);
} catch (KundeNotFoundException e) {
return ResponseEntity.notFound().build();
}
}
// DELETE /api/kunden/{id}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteKunde(@PathVariable Long id) {
service.loescheKunde(id);
return ResponseEntity.noContent().build();
}
}
// Модель данных
class Kunde {
private Long id;
private String name;
private String email;
private LocalDate geburtsdatum;
// Getter и Setter
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public LocalDate getGeburtsdatum() { return geburtsdatum; }
public void setGeburtsdatum(LocalDate geburtsdatum) { this.geburtsdatum = geburtsdatum; }
}
Рекомендуемая литература: объектно-ориентированное программирование
Keine Bücher für Kategorie "objektorientierte-programmierung" gefunden.
Концепции OOP в обзоре
Инкапсуляция
// Данные и методы объединяются в одну единицу
public class Bankkonto {
private double kontostand; // Приватные данные
public void einzahlen(double betrag) { // Публичный метод
if (betrag > 0) {
kontostand += betrag;
}
}
public double getKontostand() {
return kontostand;
}
}
Абстракция
// Сложная реальность упрощается
abstract class Fahrzeug {
protected String marke;
public abstract void beschleunigen();
public abstract void bremsen();
public void anzeigen() {
System.out.println("Fahrzeug: " + marke);
}
}
Полиморфизм
// Один интерфейс, множество реализаций
interface Tier {
void macheLaut();
}
class Hund implements Tier {
public void macheLaut() {
System.out.println("Wuff!");
}
}
class Katze implements Tier {
public void macheLaut() {
System.out.println("Miau!");
}
}
// Использование
Tier tier1 = new Hund();
Tier tier2 = new Katze();
tier1.macheLaut(); // Wuff!
tier2.macheLaut(); // Miau!
Стратегии персистентности
Сериализация
- Java Serialization: интерфейс
Serializable - JSON: удобочитаемый, платформо-независимый формат
- XML: структурированный, с метаданными
- Binary: компактный, быстрый
Персистентность на основе БД
- Реляционные БД: структурированные данные с SQL
- NoSQL БД: гибкие документы или ключ-значение
- ORM: Object-Relational Mapping
- JPA/Hibernate: Java Persistence API
Облачная персистентность
- Object Storage: S3, Azure Blob Storage
- Databases-as-a-Service: Firebase, Supabase
- Кеширование: Redis, Memcached
Типы API
Программные интерфейсы
- Local APIs: методы в одной программе
- Library APIs: внешние библиотеки
- Framework APIs: Spring, Django, React
Web-API
- REST: HTTP-методы, коды состояния
- GraphQL: гибкий язык запросов
- gRPC: высокопроизводительный RPC
- WebSocket: общение в реальном времени
Платформенные API
- OS APIs: Windows, Linux, macOS
- Mobile APIs: Android, iOS
- Cloud APIs: AWS, Azure, GCP
Преимущества и недостатки
Преимущества концепций OOP
- Структурирование: четкая организация кода
- Переиспользование: компоненты можно применять многократно
- Поддерживаемость: модульная структура облегчает изменения
- Тестируемость: изолированные компоненты легко тестировать
- Масштабируемость: системы могут расти
Недостатки
- Сложность: издержки при малых проектах
- Кривая обучения: много концепций для понимания
- Производительность: иногда медленнее, чем процедурный код
- Переусложнение: риск излишней сложности
Часто встречающиеся вопросы
-
В чём разница между атрибутом и методом? Атрибуты это свойства/данные, методы это поведение/функции объекта.
-
Объясните понятие сообщение в OOP! Сообщение это взаимодействие между объектами, обычно реализуется как вызов метода.
-
Что означает персистентность в программировании? Постоянное хранение данных, чтобы они были доступны в течение нескольких запусков программы.
-
Для чего служат интерфейсы? Определяют контракты между компонентами, позволяют ослабить связанность и обеспечить полиморфизм.
Основные источники
- https://de.wikipedia.org/wiki/Objektorientierte_Programmierung
- https://docs.oracle.com/javase/tutorial/java/concepts/
- https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/
Продолжение пути обучения OOP
Следующая статья в пути OOP рассмотрит OOP инкапсуляция: основы, информационное скрывание и видимость , как инкапсуляция скрывает внутренние состояния.



