LINUX.ORG.RU

Подскажите по созданию объекта через переменную

 , ,


0

1

Не могу разобраться, гугол замучал, но решения вопроса пока так и не нашёл.

Не в development ибо «ПО» называть этот хэллоуворлд слишком круто.

Есть 6 классов. От пользователя запрашивается какое количество и каких объектов необходимо создать. 1 = Bicycle, 2 = Bus и т.д.

Соответственно дальше мне надо вызвать метод для создания объекта.

То есть, есть такое:

autoParking.parkInTransport(new Class.forName(setTransportType)("" + lcTransportType + "" + i)); 

Мне нужно, чтобы в зависимости от выбранного пользователем значения вызывалось (new Bicycle), (new Bus) и т.д., а далее - количество этих самых объектов.

Сейчас оно у меня ругается на forName, хотя в гугле у всех всё ок. Пишет «cannot resolve symbol 'forName'». В какую сторону копать? Или как ещё можно подобное реализовать? Сильно влом пихать всю логику в каждый блок из шести только потому, что оно не может найти forName. Хотя при вводе оно знает такую конструкцию и ожидает в скобках String.

Перемещено leave из talks

★★★★

А еще у тебя какая-то каша со скобками.

kovrik ★★★★★ ()

Создавать экземпляр класса надо через newInstance()

alchemist ()

Тебе нужно использовать паттерн Factory.

Legioner ★★★★★ ()

Ну вот так, скажем, можно:

enum VehicleType{
   CAR(Car.class),
   BUS(Bus.class);
//constructor and fields omitted
   Class getVehicleClass(){
       return this.vehicleClass;
   }
}

public Vehicle createVehicle(VehicleType type){
    return type.getVehicleClass().newInstance();
} 

Deleted ()

Вот именно поэтому динамическая типизация в начале обучения программированию является по меньшей мере диверсией.

Zenom ★★★ ()

Задайте интерфейс фабрики, как белый человек:

public interface Factory {
    Object create(int qty);
}


Затем сделайте регистр фабрик:
Map<String, ClassFactory> factories = new HashMap<>();

{
    factories.put("Bicycle", new BusFactory());
    factories.put("Bus", new BusFactory());
    // ... и так далее
}


А потом уже плодите объекты, сколько влезет:
Object buses = factories.get(transportType).create(transportQty);

sanwashere ★★ ()

Для создания объекта есть оператор new, для типизации общего поведения разных объектов есть интерфейсы, для генерации разных объектов с общим интерфейсом есть фабрики. Про класс Class и все его свойства, forName и newInstance - в первую очередь, забудь вообще, они не для тебя.

bender ★★★★★ ()

Используй factory, выше уже даже пример привели.

invy ★★★★★ ()
Ответ на: комментарий от kovrik

О, спасибо, теперь вроде всё ок. Проверить пока не могу, потому что половина переписана. Но должно работать, как мне кажется.

ekzotech ★★★★ ()
Ответ на: комментарий от alchemist

Почему-то на stackoverflow пишут, что надо избегать использования newInstance(), мол, он даёт скрытый эксепшн.

ekzotech ★★★★ ()
Ответ на: комментарий от Legioner

Я ещё далёк от таких вещей. В смысле, я краем уха слышал про паттерны, но и только.

ekzotech ★★★★ ()
Ответ на: комментарий от sanwashere

Не совсем понял.

Когда я создаю интерфейс фабрики - Object create - это стандартное написание? В int qty, как я понимаю, будет лежать количество создаваемых объектов. И интерфейс фабрики создаётся один?

Про Map вроде понятно, а как я потом вызываю именно нужный мне Map? Из переменной transportType он понимает, какой из мапов мне нужен?

ekzotech ★★★★ ()
Ответ на: комментарий от ekzotech
package ru.org.linux.sample;

import java.util.HashMap;
import java.util.Map;

interface Vehicle {}

class Bus implements Vehicle {}
class Bicycle implements Vehicle {}
class PogoStick implements Vehicle {}

interface Factory {
    Vehicle[] create(int quantity);
}

class BusFactory implements Factory {
    public Bus[] create(int quantity) { return new Bus[quantity]; }
}

class BicycleFactory implements Factory {
    public Bicycle[] create(int quantity) { return new Bicycle[quantity]; }
}

class PogoStickFactory implements Factory {
    public PogoStick[] create(int quantity) { return new PogoStick[quantity]; }
}

public class SampleApp {
    private static final Map<String, Factory> FACTORIES = new HashMap<>(3);

    static {
        FACTORIES.put("Bus", new BusFactory());
        FACTORIES.put("Bicycle", new BicycleFactory());
        FACTORIES.put("PogoStick", new PogoStickFactory());
    }

    public static void main(String[] args) {
        Vehicle[] vehicles = FACTORIES.get(args[0]).create(Integer.valueOf(args[1]));
        // TODO: Process vehicle data
    }
}
sanwashere ★★ ()
Ответ на: комментарий от sanwashere

У меня есть общий класс Transport, который содержит 2 метода, и есть классы Car, Bus, Bicycle и т.д., которые его наследуют и переопределяют методы. В таком случае мне не надо же создавать интерфейс Vehicle, да?

ekzotech ★★★★ ()
Ответ на: комментарий от sanwashere

И да, Class.forName(...) - «дорогой» метод. Лучше избегать его вызова вообще где бы то ни было.

sanwashere ★★ ()
Ответ на: комментарий от ekzotech

Ничего сложного. Фабрика это такой класс, который умеет создавать другой класс.

import java.util.HashMap;
import java.util.Map;

// иерархия классов
interface Transport {}
class Bicycle implements Transport {}
class Bus implements Transport {}

// иерархия фабрик
interface TransportFactory {
    Transport create();
}
class BicycleFactory implements TransportFactory {
    @Override
    public Bicycle create() {
        return new Bicycle();
    }
}
class BusFactory implements TransportFactory {
    @Override
    public Bus create() {
        return new Bus();
    }
}

class Main {
    public static void main(String[] args) {
        // реестр фабрик, инициализация
        Map<String, TransportFactory> transportFactoryRegistry = new HashMap<>();
        transportFactoryRegistry.put("Bicycle", new BicycleFactory());
        transportFactoryRegistry.put("Bus", new BusFactory());

        // использование
        String transportType = "Bus";
        TransportFactory transportFactory = transportFactoryRegistry.get(transportType);
        Transport transport = transportFactory.create();        
    }
}

С использованием Java 8 этот случай можно записать компактней:

        Map<String, Supplier<Transport>> transportFactoryRegistry = new HashMap<>();
        transportFactoryRegistry.put("Bicycle", Bicycle::new);
        transportFactoryRegistry.put("Bus", Bus::new);

        String transportType = "Bus";
        Supplier<Transport> transportFactory = transportFactoryRegistry.get(transportType);
        Transport transport = transportFactory.get();
но суть останется та же самая.

Legioner ★★★★★ ()
Ответ на: комментарий от Legioner

А выполнение происходит как?

Вот у меня transportType получило = «Bus» при присвоении в одном из кейсов, то есть я не пишу это над блоком TransportFactory transportFactory... Оно отработает? И соответственно отработает на Car, Bicycle и т.д.?

ekzotech ★★★★ ()
Ответ на: комментарий от sanwashere
Vehicle[] vehicles = FACTORIES.get(args[0]).create(Integer.valueOf(args[1]));

Как мне в эту строку передать значение с именем класса, объект которого надо создать?

Есть переменная transportType, которая получает значение от 1 до 6 (что введёт пользователь), 1 означает Bicycle, 2 означает Bus и т.д.

А далее я запрашиваю количество объектов для выбранного класса, и соответственно создаю необходимое количество. У тебя в коде реализовано int quantity, значит в неё передам количество.

И вот как мне это засунуть в вышеуказанную строку? Пока не могу понять что-то.

ekzotech ★★★★ ()
Ответ на: комментарий от Legioner

А куда можно скормить количество создаваемых объектов в твоём варианте?

ekzotech ★★★★ ()
Ответ на: комментарий от ekzotech

* Поменяйте тип ключа для Map в поле «FACTORIES» на Integer и делайте .put(1, ...) и т.д. Это позволит получать фабрики по ключу. Или вообще перевести Map<> FACTORIES на массив, если индексы типов идут по порядку.
* Вместо Integer.parseInt(...) лучше использовать метод Integer.valueOf(...), так как ввод вида «020» обработается как число с восьмеричным основанием и дат 16, а не 20, как ожидается.

sanwashere ★★ ()
Ответ на: комментарий от sanwashere

* Вместо Integer.parseInt(...) лучше использовать метод Integer.valueOf(...), так как ввод вида «020» обработается как число с восьмеричным основанием и дат 16, а не 20, как ожидается.

С JavaScript-ом путаешь. В Java до такого маразма не додумались, слава Гослингу.

Legioner ★★★★★ ()
Ответ на: комментарий от sanwashere

Вместо Integer.parseInt(...) лучше использовать метод Integer.valueOf(...)

Наоборот.

так как ввод вида «020» обработается как число с восьмеричным основанием и дат 16, а не 20, как ожидается.

Нет.

korvin_ ★★★★★ ()
Ответ на: комментарий от Legioner

Я перепутал с методом Integer.decode(...) - так что додумались =)

sanwashere ★★ ()
Ответ на: комментарий от sanwashere

Действительно, и такое там есть. Не замечал раньше.

Legioner ★★★★★ ()
Ответ на: комментарий от sanwashere

А где можно подробно почитать про всю эту конструкцию, которую ты сделал?

А то я что-то понял, но не всё.

ekzotech ★★★★ ()
Ответ на: комментарий от sanwashere

О, спасибо прям огромное за помощь!

Сижу разбираюсь.

Теперь осталось по мелочи дописать, и, самое главное - превратить мой процедур-стайл код в труЪ-ООП. Ибо у меня почти всё напихано в основной класс.

ekzotech ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.