как создать абстрактную фабрику для создания экземпляров объектов в Java

#java #abstract-factory

#java #абстрактная фабрика

Вопрос:

Я хотел бы создать абстрактную фабрику. вот что я попробовал.

// абстрактный рабочий класс

 public abstract class Worker {
    String phoneNumber;
    String firstName;
    String lastName;
    String workerType;
    String ifu;
    String imageParth;
    //....
  public String getWorkerType() {
        return workerType;
    }
}
 

// Класс электрика, который расширяет worker

 package worker.domain.worker;

public class Electrician extends Worker{
    
    
    public Electrician() {}
    public Electrician(String phoneNumber, String firstName, String lastName, String ifu, String workerType,
            String imageParth) {
        super(phoneNumber, firstName, lastName, ifu,workerType, imageParth);
    }
    
    
    public String getWorkerType() {
        return "Electrician";
    }
    
}
 

// Класс Мейсона

 package worker.domaine.worker;

public class Mason extends Worker{
    
    public Mason() {};

    public Mason(String phoneNumber, String firstName, String lastName, String ifu,String workerType,
            String imageParth) {
        super(phoneNumber, firstName, lastName, ifu, workerType, imageParth);
    }
    
    String getworkerType() {
        return "Mason";
    }
}
 

// interface WorkerAbstractFactory

 package worker.domaine.worker;

public interface WorkerAbstractFactory {
    Worker createWorker(String typeWorker);
}
 

//

 public class WorkerFactory implements WorkerAbstractFactory{

    @Override
    public Worker createWorker(String typeWorker) {
        Worker worker = null;
        if(worker != null) {
            switch (typeWorker) {
            case "Electrician":
                Electrician electrician =new Electrician();
                electrician = new Electrician (electrician.getPhoneNumber(), electrician.getFirstName(), electrician.getLastName(), electrician.getIfu(), electrician.getWorkerType(),electrician.getImageParth());
                
            case "Mason":
                Mason mason =new Mason();
                mason = new Mason (mason.getPhoneNumber(), mason.getFirstName(), mason.getLastName(), mason.getIfu(), mason.getworkerType(),mason.getImageParth());
                }}
 

// класс приложения

 public class WorkerFactoryProvider {
    
     public static WorkerAbstractFactory getWorkerFactory(String workerCategory) {
         //WorkerFactory workerFactory = new WorkerFactory();
         WorkerFactory workerFactory = new WorkerFactory();
         if (workerCategory != null) {
             switch (workerCategory) {
                case "Electrician":
                    Worker worker1 = workerFactory.createWorker("Electrician");
                    worker1.getWorkerType();
                    String a=worker1.getWorkerType();
                    System.out.println(a);  
                    
                case "Mason":
                    Worker worker2 = workerFactory.createWorker("Mason");
                    worker2.getWorkerType();
                    String b=worker2.getWorkerType();
                    System.out.println(b);               
             
             }
             
             
         }
         return null;
     }
 

как вы думаете, это может так работать? теперь, если я действительно хочу конкретный объект, как это можно сделать? потому что я хотел бы написать, например, метод для расчета заработной платы каждого работника в зависимости от типа, например, как я мог бы использовать свою абстрактную фабрику в методе, чтобы возвращать мне каждый тип.

Комментарии:

1. Примечание: вам необходимо передать все эти поля PhoneNumber и т.д. на фабрику, чтобы она могла создавать экземпляр Worker. В качестве альтернативы, пусть фабрика создаст WorkerBuilder, соответствующий базовому типу.

2. Добро пожаловать в StackOverflow. Ваш первый вопрос: «Как вы думаете, это может так работать», запрашивает мнение. Есть ли (каламбур) конкретный вопрос, который вы хотели бы задать?

Ответ №1:

У вас есть единая иерархия классов рабочих типов. Для их создания вы можете просто использовать отдельный класс factory, здесь вам не нужна абстрактная фабрика. Например, этого было бы достаточно:

 public class WorkerFactory {            
    public Worker createWorker(String workerType) {
        switch (workerType) {
            case "Electrician": return new Electrician();                    
            case "Mason": return new Mason();
        }
    }
}
 

Шаблон абстрактной фабрики более сложный и позволяет вводить разные конкретные фабрики для связанных иерархий объектов, так что клиенту не нужно знать о разнице. Например, у вас может быть абстрактный TransportationFactory:

 interface Transportation {
    void travelTo(String destination);
}

interface TransportationFactory {
    Transportation simple();
    Transportation luxurious();
}
 

И две конкретные реализации (соответствующие двум разным, но похожим иерархиям классов):

 class WaterTransportationFactory {
   Transportation simple() {
       return new Kayak();
   }
   Transportation luxurious() {
       return new Yacht();
   }
}
 

И:

 class LandTransportationFactory {
   Transportation simple() {
       return new Bike();
   }
   Transportation luxurious() {
       return new RaceCar();
   }
}
 

Преимущество этого шаблона в том, что клиент может быть настроен на использование водного или наземного транспорта (или нового воздушного транспорта, который будет добавлен позже) без необходимости внесения каких-либо изменений:

 class Client {

    private TransportationFactory transportationFactory;

    public Client(TransportationFactory transportationFactory) {
        this.transportationFactory = transportationFactory;
    }

    public void travel(String destination) {
        transportationFactory.simple().travelTo(destination);
    }

    public void travelInStyle(String destination) {
        transportationFactory.luxurious().travelTo(destination);
    }

}
 

РЕДАКТИРОВАТЬ: вы можете изменить простые / роскошные методы, чтобы они соответствовали стилю вашего примера с getWorkerType помощью метода. Я предпочитаю избегать условной логики, если это возможно, и позволяю созданным классам самим определять их доступность. Это еще больше разъединяет, позволяя добавлять элементы иерархии с минимальными изменениями кода:

 enum TransportationType {
    SIMPLE, LUXURIOUS
}

interface Transportation {

    void travelTo(String destination);

    // allow the class to specify its own type
    TransportationType getType();
}

// intermediate interface to distinguish Water from Land
interface WaterTransportation extends Transportation {
}

class Kayak implements WaterTransportation {

    void travelTo(String destination) {
        // splash splash
    }

    TransportationType getType() {
        return TransportationType.SIMPLE;
    }
}

class WaterTransportationFactory {

   private WaterTransportation[] waterTransportations;

   // Inject all available beans implementing WaterTransportation
   // e.g. using Spring or some other dependency injection mechanism
   public WaterTransportationFactory(WaterTransportation[] waterTransportations) {
       this.waterTransportations = waterTransportations;
   }

   public Transportation create(TransportationType type) {
       for(WaterTransportation waterTransportation : waterTransportations) { 
           if (waterTransportation.getType() == type) {
               // we are returning the same instance every time
               // this could be ok for singleton beans
               // but if you really need a fresh instance you could use builders (see below)
               return waterTransportation;
           }
       }
       throw new IllegalArgumentException("No implementation for WaterTransportation type="   type);
   }
}
 

Альтернатива со сборщиками:

 KayakBuilder implements WaterTransportationBuilder {
    KayakBuilder name(String name) { ... };
    KayakBuilder weight(String weightInKg) { ... };
    KayakBuilder year(String yearBuilt) { ... };
    KayakBuilder speed(String averageSpeed) { ... };
    Kayak build() { return kayak; }
}
 

Для получения дополнительной информации о сборщиках см. Это Полное Изложение шаблона Builder

 class WaterTransportationFactory {

   private WaterTransportationBuilder[] builders;

   // Inject all available WaterTransportationBuilders
   // e.g. using Spring or some other dependency injection mechanism
   public WaterTransportationFactory(WaterTransportationBuilder[] builders) {
       this.builders = builders;
   }

   // extra arguments can be passed to build the instance
   public Transportation create(TransportationType type, String name, int weightInKg, int yearBuilt, int averageSpeed) {
       for(WaterTransportationBuilder builder: builders) { 
           if (builder.getType() == type) {
               return builder
                   .name(name)
                   .weight(weightInKg)
                   .year(yearBuilt)
                   .speed(averageSpeed)
                   .build();
           }
       }
       throw new IllegalArgumentException("No implementation for WaterTransportation type="   type);
   }
}