Приведите пример класса в Java, нарушающего принципы SOLID, опишите проблему и предложите рефакторинг

17 Фев в 15:59
16 +1
0
Ответы
1
Пример «плохого» класса, нарушающего принципы SOLID, кратко объяснение проблем и предложенный рефакторинг.
Плохой класс (смешивает много обязанностей — чтение данных, форматирование, запись в файл, отправку почты):
```
public class ReportManager {
public void generateAndSendReport() {
// 1. Получить данные из БД
List rows = new ArrayList();
try (Connection c = DriverManager.getConnection("jdbc:db://...")) {
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("SELECT name, value FROM items");
while (rs.next()) {
rows.add(rs.getString("name") + "," + rs.getString("value"));
}
} catch (SQLException e) {
e.printStackTrace();
}
// 2. Сформировать CSV
StringBuilder csv = new StringBuilder();
csv.append("name,value\n");
for (String r : rows) csv.append(r).append("\n");
// 3. Сохранить в файл
try (FileWriter fw = new FileWriter("/tmp/report.csv")) {
fw.write(csv.toString());
} catch (IOException e) {
e.printStackTrace();
}
// 4. Отправить по почте
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.example.com");
Session session = Session.getInstance(props);
try {
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("noreply@example.com"));
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("user@example.com"));
msg.setSubject("Report");
msg.setText("See attached");
// прикрепление файла опущено
Transport.send(msg);
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
```
Какие принципы SOLID нарушены и почему:
- Single Responsibility Principle: класс делает сразу несколько задач — доступ к данным, форматирование, сохранение, отправка почты. Изменение любого поведения (новая БД, новый формат, другой способ доставки) потребует правок в одном классе.
- Open/Closed Principle: чтобы добавить новый формат (JSON, XML) или сменить доставку (SFTP), нужно менять код метода, а не расширять поведение через новые реализации.
- Dependency Inversion: класс жестко зависит от конкретных механизмов (JDBC, FileWriter, JavaMail), а не от абстракций — тестирование и замена реализаций затруднены.
- Interface Segregation (в косвенной форме): один класс вынужден «знать» и реализовывать всё, чего клиентам может не требоваться.
Рефакторинг: разделить обязанности через интерфейсы, использовать внедрение зависимостей (constructor injection). Короткая схема.
Интерфейсы:
```
public interface DataProvider {
List fetch();
}
public interface Formatter {
byte[] format(List data);
}
public interface Storage {
void save(String path, byte[] content);
}
public interface Notifier {
void send(String subject, String body, String attachmentPath);
}
```
Примеры реализаций (кратко):
```
public class DatabaseProvider implements DataProvider {
public List fetch() {
// реализация JDBC...
}
}
public class CsvFormatter implements Formatter {
public byte[] format(List data) {
// собрать CSV и вернуть bytes
}
}
public class FileStorage implements Storage {
public void save(String path, byte[] content) {
Files.write(Paths.get(path), content);
}
}
public class SmtpNotifier implements Notifier {
public void send(String subject, String body, String attachmentPath) {
// реализация JavaMail
}
}
```
Высокоуровневый класс, зависящий от абстракций:
```
public class ReportService {
private final DataProvider provider;
private final Formatter formatter;
private final Storage storage;
private final Notifier notifier;
public ReportService(DataProvider provider, Formatter formatter, Storage storage, Notifier notifier) {
this.provider = provider;
this.formatter = formatter;
this.storage = storage;
this.notifier = notifier;
}
public void generateAndSend(String path) {
List data = provider.fetch();
byte[] content = formatter.format(data);
storage.save(path, content);
notifier.send("Report", "See attached", path);
}
}
```
Преимущества рефакторинга:
- Соблюдается Single Responsibility: каждый класс — одна ответственность.
- Open/Closed: добавить новый формат или способ доставки — реализовать новый Formatter или Notifier без правки ReportService.
- Dependency Inversion: ReportService зависит от абстракций (интерфейсов), не от конкретных библиотек.
- Легче тестировать (подменять мок-реализации интерфейсов), расширять и поддерживать.
Краткая рекомендация: выделяйте границы ответственности сразу, применяйте интерфейсы и внедрение зависимостей — это значительно уменьшает связность и повышает гибкость.
17 Фев в 16:04
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир