Java - статический метод фабрики и операторы переключения

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

Текущая реализация для построения этих сообщений примерно следующие:

public static Message fromMap(int uuid, Map fields) {
    switch (uuid) {
      case FIRST_MESSAGE_ID:
        return new FirstMessage(fields);
        .
        .
        .
      default:
          // Error
          return null;
    }
}

public static Message fromByteBuffer(int uuid, ByteBuffer buffer) {
    switch (uuid) {
      case FIRST_MESSAGE_ID:
        return new FirstMessage(buffer);
        .
        .
        .
      default:
          // Error
          return null;
    }
}

Теперь, Эффективный Java Josh Bloch говорит об Объекте 1: Рассмотрите статические методы фабрики вместо конструкторов, и это, кажется, место, где этот шаблон полезен (клиенты непосредственно не получают доступ к конструкторам подтипов сообщения; вместо этого они проходят этот метод). Но мне не нравится то, что мы должны не забыть держать два оператора переключения в курсе (нарушает принцип DRY).

Я ценил бы любое понимание лучшего способа выполнить это; мы не кэшируем объекты (каждый вызов к fromMap, или fromByteBuffer возвратит новый объект), который инвертирует часть преимущества использования статического метода фабрики как это. Что-то об этом коде кажется мне неправильно, таким образом, я хотел бы услышать мысли сообщества о том, является ли это допустимым способом создать новые объекты, или если бы не, каково лучшее решение было бы.

7
задан dave4420 11 January 2010 в 17:04
поделиться

8 ответов

Может быть, вы можете создать интерфейс MessageFactory и реализации IT:

public interface MessageFactory {
   Message createMessage(Map<String, Object> fields);
   Message createMessage(ByteBuffer buffer);
}

public class FirstMessageFactory implements MessageFactory {
  public Message createMessage(Map<String, Object> fields){
    return new FirstMessage(fields);
  }

  public Message createMessage(ByteBuffer buffer){
    return new FirstMessage(buffer);
  }

}

Далее, метод GetFactoryFromid в том же классе, что и способы выше:

public static MessageFactory getMessageFactoryFromId(int uuid){
 switch (uuid) {
  case FIRST_MESSAGE_ID:
    return new FirstMessageFactory();
    ...
  default:
      // Error
      return null;
  }
}

Однако вместо этого лучше создать hashmap IDS и фабрики, поэтому вам не нужно создавать новый заводский объект каждый раз, когда вы создаете сообщение. Смотрите также комментарий ниже .

И ваши методы:

public static Message fromMap(int uuid, Map<String, Object> fields)  {
  getMessageFactoryFromId(uuid).createMessage(fields);
}

public static Message fromByteBuffer(int uuid, ByteBuffer buffer) {
  getMessageFactoryFromId(uuid).createMessage(buffer);
}

Таким образом, вы используете заводской шаблон, и нет необходимости иметь два раза одни и те же оператор коммутатора.

(не проверил это, так, возможно, некоторые ошибки компиляции / опечатки)

12
ответ дан 6 December 2019 в 09:19
поделиться

Если у вас есть свои объекты, реализующие интерфейс, объявляющие заводские методы, такие как:

public Message newInstance(Map<String, Object> fields);
public Message newInstance(ByteBuffer buffer);

в статическом вложенном классе, ваш завод может создать карту , содержащую заводские объекты, индексируемые UUID:

Map map = new HashMap();

map.put(Integer.valueOf(FirstMessage.UUID), new FirstMessage.Factory());

и замените выключатели по поиску карты:

public static Message fromMap(int uuid, Map<String, Object> fields) {

    Factory fact = map.get(Integer.valueOf(uuid));

    return (null == fact) ? null : fact.newInstance(fields);
}

public static Message fromByteBuffer(int uuid, ByteBuffer buffer) {

    Factory fact = map.get(Integer.valueOf(uuid));

    return (null == fact) ? null : fact.newInstance(buffer);
}

Это может быть легко расширено для поддержки других методов строительства.

3
ответ дан 6 December 2019 в 09:19
поделиться

Трудно отсоединить вашу продукцию DB или другой бегущую БД и иметь дело с этим временем простоя, поэтому я почти всегда использую метод резервной копии / восстановления.

Если вы также хотите обеспечить синхронизацию вашего входа в систему, проверьте статью MS KB на использовании хранимых ProC SP_HELP_REVLOGIN .

-121--867648-

TEM 1: рассмотрите статические фабричные методы вместо конструкторов

Вы делаете это уже, скрывая конструктор за этим заводским методом, поэтому нет необходимости добавлять еще один заводский метод.

Итак, вы можете сделать это с заводским интерфейсом и картой. (В основном то, что все уже говорят, но с разницей, что вы можете встроить фабрики, используя внутренние классы)

interface MessageFactory {
    public Message createWithMap( Map<String,Object> fields );
    public Message createWithBuffer( ByteBuffer buffer );
}

Map<MessageFactory> factoriesMap = new HashMap<MessageFactory>() {{
    put( FIRST_UUID, new MessageFactory() {
        public Message createWithMap( Map<String, Object> fields ) {
            return new FirstMessage( fields );
        }
        public Message createWithBuffer( ByteBuffer buffer ){ 
            return new FirstMessage( buffer );
        }
    } );
    put( SECOND_UUID, new MessageFactory(){
        public Message createWithMap( Map<String, Object> fields ) {
            return new SecondMessage( fields );
        }
        public Message createWithBuffer( ByteBuffer buffer ){ 
            return new SecondMessage( buffer );
        } 
    } );
    put( THIRD_UUID, new MessageFactory(){
        public Message createWithMap( Map<String, Object> fields ) {
            return new ThirdMessage( fields );
        }
        public Message createWithBuffer( ByteBuffer buffer ){ 
            return new ThirdMessage( buffer );
        } 
    } );
    ...
}};

, и ваши вызова будут превращены в:

public static Message fromMap(int uuid, Map<String, Object> fields) {
    return YourClassName.factoriesMap.get( uuid ).createWithMap( fields );
}

public static Message fromByteBuffer(int uuid, ByteBuffer buffer) {
    return YourClassName.factoriesMap.get(uuid).createWithBuffer( buffer );
}

, потому что UUID, используемый для выключателя, используется в качестве ключа для заводов. Отказ

3
ответ дан 6 December 2019 в 09:19
поделиться

Я рекомендую использовать тип enum с абстрактными методами, таким как следующий пример:

enum MessageType {

    FIRST_TYPE(FIRST_MESSAGE_ID) {

        @Override
        Message fromByteBuffer(ByteBuffer buffer) {
            return new FirstMessage(buffer);
        }

        @Override
        Message fromMap(Map<String, Object> fields) {
            return new FirstMessage(fields);
        }

        @Override
        boolean appliesTo(int uuid) {
            return this.uuid == uuid;
        }

    },

    SECOND_TYPE(SECOND_MESSAGE_ID) {

        @Override
        Message fromByteBuffer(ByteBuffer buffer) {
            return new SecondMessage(buffer);
        }

        @Override
        Message fromMap(Map<String, Object> fields) {
            return new SecondMessage(fields);
        }

        @Override
        boolean appliesTo(int uuid) {
            return this.uuid == uuid;
        }

    };

    protected final int uuid;

    MessageType(int uuid) {
        this.uuid = uuid;
    }

    abstract boolean appliesTo(int uuid);

    abstract Message fromMap(Map<String, Object> map);

    abstract Message fromByteBuffer(ByteBuffer buffer);

}

Таким образом, в ваших существующих статических методах вы можете просто сделать это ...

public static Message fromByteBuffer(int uuid, ByteBuffer buffer) {
    Message rslt = null;
    for (MessageType y : MessageType.values()) {
        if (y.appliesTo(uuid)) {
            rslt = y.fromByteBuffer(buffer);
            break;
        }
    }
    return rslt;
}

Этот подход Сохраняет ваш статический метод от необходимости знать о поддержке, которые вы поддерживаете и как их построить - вы можете добавить, изменять или удалять сообщения без рефакторов статических методов.

1
ответ дан 6 December 2019 в 09:19
поделиться

Вы можете изменить сообщение так, чтобы он имеет два метода инициализации, один для карты и один для Bytebuffer (вместо двух версий Cretuctor). Тогда ваш фабричный метод возвращает построенное (но неинициализированное) сообщение, затем вы вызываете инициализацию с картой или ByTeBuffer на возвращенном объекте.

Итак, теперь у вас есть заводский метод, подобный этому: -

private static Message createMessage(int uuid) {
    switch (uuid) {
      case FIRST_MESSAGE_ID:
        return new FirstMessage();
        .
        .
        .
      default:
          // Error
          return null;
    }

}

, а затем общественные фабрики методы становятся: -

public static Message fromMap(int uuid, Map<String, Object> fields) {
  Message message = createMessage(uuid);
  // TODO: null checking etc....
  return message.initialize(fields);
}

и

public static Message fromByteBuffer(int uuid, ByteBuffer buffer) {
  Message message = createMessage(uuid);
  // TODO: null checking etc....
  return message.initialize(buffer);
}
0
ответ дан 6 December 2019 в 09:19
поделиться

Вы должны абстрагироваться от вашего FirstMessage объекта:

public abstract Message {
   // ...
}

Затем кэшировать их на вашем заводе (в отличие от переключателя):

private static final Map<Integer, Class<Message>> MESSAGES = new HashMap<Integer, Class<Message>>();
static {
    MESSAGES.put(1, FirstMessage.class);
}

В вашем заводском методе:

public static Message fromMap(UUID uuid, Map<String, Object> fields) {
    return MESSAGES.get(uuid).newInstance();
}

В любом случае, это просто идея, вам нужно будет сделать несколько отражений (заставить конструктор) работать, чтобы передать поля.

0
ответ дан 6 December 2019 в 09:19
поделиться

Вы Может использовать форму абстрактных шаблон , где у вас будет заводский класс для каждого типа сообщения, который возвращает вам сообщение либо по буферу, либо на карте. Затем вы создаете метод, который возвращает вам соответствующий заводский объект. С возвращенной фабрики вы тогда создаете сообщение.

0
ответ дан 6 December 2019 в 09:19
поделиться

SQL Server оптимизирован для одновременного выполнения нескольких операций чтения. Единственный раз, когда вы можете столкнуться с взаимоблокировкой, это если у вас много операций обновления происходит в той же таблице, к которой вы пытаетесь получить доступ. Однако в этом случае можно использовать nolock или даже установить уровень изоляции транзакции на READ UNCOMMITTED .

Теперь в отношении вашего вопроса многопоточности. В SQL Server используется что-то, называемое волокнами, которые похожи на подпоток. Таким образом, вы не обязательно увидите то же масштабирование потока процессора, которое вы ожидаете увидеть в многопроцессорной среде. Хотя SQL Server имеет доступ к определенному числу потоков, существует максимальное количество волокон, которые также могут использоваться. Вот почему вы можете иметь 1000 клиентов, имеющих доступ к одному и тому же серверу одновременно даже на небольших коробках.

Если вы действительно хотите попасть в планирование потоков/оптоволокна, вам нужно будет найти хорошего гаек и болтов SQL Server, который действительно действительно получает его, как это сложно.

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

-121--3802394-

Необходимо создать мутатор для изменения частных переменных-членов.

class example{
    private string myColor;
    public void changeColor(string newColor){
        myColor = newColor;
    }
}
-121--2296102-

Есть ли способ преобразовать ByteBuffer в карту или что-то еще? Было бы неплохо преобразовать входные данные в нормализованную форму и применить уникальный переключатель.

Если вы хотите получить сообщение и отформатировать его с определенными значениями (например, «Таблица: taureName не имеет столбца с именем: colName»), вы можете преобразовать ByteBuffer в карту и вызвать первый метод. Если вам нужен новый идентификатор msgId, вы расширяете только метод startMap Map.

Это что-то вроде факторинга общей части.

1
ответ дан 6 December 2019 в 09:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: