Assistant: 
User: User: посмотри на мой код. как убрать повторяющийся код в инициализации класса
может передавать изменяющиеся параметры в виде списка

и уже в цикле применять

```
package com.shop.controllers.admin;

import com.shop.database.DbConnection;
import com.shop.database.models.Processor;
import com.shop.helper.AlertHelper;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.stage.Window;
import javafx.util.converter.IntegerStringConverter;
import javafx.util.converter.BigDecimalStringConverter;

import java.math.BigDecimal;
import java.net.URL;
import java.util.ResourceBundle;

public class AdminProcessorsController implements Initializable {
    @FXML
    private TableView<Processor> tableView;
    @FXML
    private TableColumn<Processor, String> nameColumn;
    @FXML
    private TableColumn<Processor, String> brandColumn;
    @FXML
    private TableColumn<Processor, Integer> coresColumn;
    @FXML
    private TableColumn<Processor, Integer> threadsColumn;
    @FXML
    private TableColumn<Processor, BigDecimal> baseClockColumn;
    @FXML
    private TableColumn<Processor, BigDecimal> boostClockColumn;
    @FXML
    private TableColumn<Processor, String> linkColumn;

    Window window;

    @FXML
    private Button saveButton;
    @FXML
    private Button addButton;
    @FXML
    private Button deleteButton;

    private ObservableList<Processor> processorsList = FXCollections.observableArrayList();

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
        nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
        nameColumn.setOnEditCommit(event -> {
            Processor processor = event.getRowValue();
            processor.setName(event.getNewValue());
        });
        brandColumn.setCellValueFactory(new PropertyValueFactory<>("brand"));
        brandColumn.setCellFactory(TextFieldTableCell.forTableColumn());
        brandColumn.setOnEditCommit(event -> {
            Processor processor = event.getRowValue();
            processor.setBrand(event.getNewValue());
        });
        coresColumn.setCellValueFactory(new PropertyValueFactory<>("cores"));
        coresColumn.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
        coresColumn.setOnEditCommit(event -> {
            Processor processor = event.getRowValue();
            try {
                processor.setCores(event.getNewValue());
            } catch(Exception e) {
                window = addButton.getScene().getWindow();
                AlertHelper.showAlert(Alert.AlertType.ERROR, window, "Error",
                    "The value in the “cores” column must be a number");
            }
        });

        threadsColumn.setCellValueFactory(new PropertyValueFactory<>("threads"));
        threadsColumn.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
        threadsColumn.setOnEditCommit(event -> {
            Processor processor = event.getRowValue();
            try {
                processor.setThreads(event.getNewValue());
            } catch(Exception e) {
                window = addButton.getScene().getWindow();
                AlertHelper.showAlert(Alert.AlertType.ERROR, window, "Error",
                    "The value in the “threads” column must be a number");
            }
        });

        baseClockColumn.setCellValueFactory(new PropertyValueFactory<>("baseClock"));
        baseClockColumn.setCellFactory(TextFieldTableCell.forTableColumn(new BigDecimalStringConverter()));
        baseClockColumn.setOnEditCommit(event -> {
            Processor processor = event.getRowValue();
            try {
                processor.setBaseClock(event.getNewValue());
            } catch(Exception e) {
                window = addButton.getScene().getWindow();
                AlertHelper.showAlert(Alert.AlertType.ERROR, window, "Error",
                    "The value in the “Base Clock” column must be a decimal");
            }
        });

        boostClockColumn.setCellValueFactory(new PropertyValueFactory<>("boostClock"));
        boostClockColumn.setCellFactory(TextFieldTableCell.forTableColumn(new BigDecimalStringConverter()));
        boostClockColumn.setOnEditCommit(event -> {
            Processor processor = event.getRowValue();
            try {
                processor.setBoostClock(event.getNewValue());
            } catch(Exception e) {
                window = addButton.getScene().getWindow();
                AlertHelper.showAlert(Alert.AlertType.ERROR, window, "Error",
                    "The value in the “Boost Clock” column must be a decimal");
            }
        });

        linkColumn.setCellValueFactory(new PropertyValueFactory<>("link"));
        linkColumn.setCellFactory(TextFieldTableCell.forTableColumn());
        linkColumn.setOnEditCommit(event -> {
            Processor processor = event.getRowValue();
            processor.setLink(event.getNewValue());
        });


        loadData();
        tableView.setItems(processorsList);
    }

    private void loadData() {
        processorsList.clear();
        processorsList.addAll(DbConnection.getDatabaseConnection().getAllProcessors());
    }

    @FXML
    private void handleSave() {
        for (Processor proc : processorsList) {
            if (
                proc.getName() == null || proc.getName().isEmpty() || 
                proc.getBrand() == null || proc.getBrand().isEmpty() ||
                proc.getCores() == null ||
                proc.getThreads() == null ||
                proc.getBaseClock() == null ||
                proc.getBoostClock() == null ||
                proc.getLink() == null || proc.getLink().isEmpty()) {
                continue;
            }

            if (proc.getId() == null) {
                DbConnection.getDatabaseConnection().addProcessor(proc);
            } else {
                DbConnection.getDatabaseConnection().updateProcessor(proc);
            }
        }

        loadData();
    }
 
    @FXML
    private void handleAdd() {
        Processor newProc = new Processor(null, null, null, null, null, null, null, null);
        processorsList.add(newProc);
        tableView.refresh();
    }

    @FXML
    private void handleDelete() {
        Processor selectedProcessor = tableView.getSelectionModel().getSelectedItem();
        if (selectedProcessor != null) {
            processorsList.remove(selectedProcessor);
            if (selectedProcessor.getId() != null) {
                DbConnection.getDatabaseConnection().deleteProcessor(selectedProcessor.getId());
            }
            tableView.refresh();
        }
    }
}
```

исправь пожалуйста код. Если что учти что мне потом нужно для других моделей делать. копировать этот код и менять.
вместо процессора вставлять gpu, ram и т.д
Поэтому сделай так чтобы мне было удобно. Чтобы я просто все поменял в одном месте и всё...
Assistant: Конечно, для улучшения кода и облегчения дальнейшего использования можно использовать обобщенный подход, который позволит уменьшить дублирование и повысить гибкость. Мы можем создать вспомогательный метод для настройки `TableColumn` и упростить инициализацию. Давайте разберёмся, как это сделать.

1. **Использование вспомогательного метода для настройки колонок**: Мы создадим метод, который будет принимать столбец, имя свойства, генератор ячеек и обработчик событий. Это позволит сократить количество кода и упростить его поддержку.

2. **Параметризация модели**: Определите свойства модели, которые могут изменяться для других типов данных (например, GPU, RAM), чтобы удобно управлять заменой.

Вот пример, как можно переработать код с учетом указанных принципов:

```java
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.StringConverter;

import java.math.BigDecimal;
import java.net.URL;
import java.util.ResourceBundle;

public class AdminProcessorsController<T> implements Initializable {
    @FXML
    private TableView<T> tableView;
    @FXML
    private TableColumn<T, String> nameColumn;
    @FXML
    private TableColumn<T, String> brandColumn;
    @FXML
    private TableColumn<T, Integer> coresColumn;
    @FXML
    private TableColumn<T, Integer> threadsColumn;
    @FXML
    private TableColumn<T, BigDecimal> baseClockColumn;
    @FXML
    private TableColumn<T, BigDecimal> boostClockColumn;
    @FXML
    private TableColumn<T, String> linkColumn;
    
    private ObservableList<T> itemList = FXCollections.observableArrayList();

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        initColumn(nameColumn, "name", TextFieldTableCell.forTableColumn(), Processor::setName);
        initColumn(brandColumn, "brand", TextFieldTableCell.forTableColumn(), Processor::setBrand);
        initColumn(coresColumn, "cores", TextFieldTableCell.forTableColumn(new IntegerStringConverter()), Processor::setCores, "The value in the “cores” column must be a number");
        initColumn(threadsColumn, "threads", TextFieldTableCell.forTableColumn(new IntegerStringConverter()), Processor::setThreads, "The value in the “threads” column must be a number");
        initColumn(baseClockColumn, "baseClock", TextFieldTableCell.forTableColumn(new BigDecimalStringConverter()), Processor::setBaseClock, "The value in the “Base Clock” column must be a decimal");
        initColumn(boostClockColumn, "boostClock", TextFieldTableCell.forTableColumn(new BigDecimalStringConverter()), Processor::setBoostClock, "The value in the “Boost Clock” column must be a decimal");
        initColumn(linkColumn, "link", TextFieldTableCell.forTableColumn(), Processor::setLink);

        loadData();
        tableView.setItems(itemList);
    }

    private <S, R> void initColumn(TableColumn<S, R> column, String property, Callback<TableColumn<T, R>, TableCell<T, R>> cellFactory, BiConsumer<Processor, R> setter) {
        column.setCellValueFactory(new PropertyValueFactory<>(property));
        column.setCellFactory(cellFactory);
        column.setOnEditCommit(event -> {
            T item = event.getRowValue();
            R newValue = event.getNewValue();
            setter.accept((Processor)item, newValue);
        });
    }

    private <S, R> void initColumn(TableColumn<S, R> column, String property, Callback<TableColumn<T, R>, TableCell<T, R>> cellFactory, BiConsumer<Processor, R> setter, String errorMessage) {
        column.setCellValueFactory(new PropertyValueFactory<>(property));
        column.setCellFactory(cellFactory);
        column.setOnEditCommit(event -> {
            T item = event.getRowValue();
            try {
                R newValue = event.getNewValue();
                setter.accept((Processor)item, newValue);
            } catch(Exception e) {
                Window window = addButton.getScene().getWindow();
                AlertHelper.showAlert(Alert.AlertType.ERROR, window, "Error", errorMessage);
            }
        });
    }

    private void loadData() {
        itemList.clear();
        itemList.addAll(DbConnection.getDatabaseConnection().getAllProcessors());
    }

    // Остальные методы...
}
```

В этом коде:
- Мы определили `initColumn`, которая настраивает `TableColumn`.
- Использование `Processor::setName` и других сеттеров для автоматической установки значений свойств.
- Ошибочные сообщения обрабатываются внутри `initColumn`.

Теперь, при изменении модели, нужно будет только обновить соответствующие места в контроллере для обработки нового типа данных как `GPU`, `RAM`, т.д.
User: а откуда Callback импортировать?
Assistant:
Assistant: