Каков наиболее адекватный шаблон для неизменяемых объектов, которые вычисляются после использования в любом месте приложения? [Дубликат]

  1. Java не поддерживает множественное наследование, а это значит, что вы можете расширять только один класс на Java, поэтому, как только вы расширили Thread класс, вы потеряли свой шанс и не можете расширять или наследовать другой класс на Java.
  2. В объектно-ориентированном программировании расширение класса обычно означает добавление новых функций, изменение или улучшение поведения. Если мы не делаем каких-либо изменений на Thread, чем используем интерфейс Runnable. Интерфейс
  3. Runnable представляет собой Task, который может быть выполнен либо обычным Thread, либо Executors или любые другие средства. Таким образом, логическое разделение Task как Runnable, чем Thread, является хорошим конструктивным решением.
  4. Отделяющая задача как Runnable означает, что мы можем повторно использовать задачу, а также иметь возможность выполнять ее с разных средств. Поскольку вы не можете перезапустить Thread после его завершения, снова Runnable vs Thread для задачи, Runnable является победителем.
  5. Разработчик Java распознает это, и именно поэтому Executors принимает Runnable ] как Task, и у них есть рабочий поток, который выполняет эту задачу.
  6. Наследование всех методов Thread - дополнительные накладные расходы только для представления функции Task, которая может быть легко выполнена с помощью Runnable.
18
задан Doug 11 August 2016 в 05:04
поделиться

1 ответ

См. также lazy_static , что делает вещи немного более эргономичными. Это по существу то же самое, что и статическая Once для каждой переменной, но обертывает ее типом, который реализует Deref, чтобы вы могли получить к нему доступ, как обычная ссылка.

Использование выглядит так ( из документации ):

#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;

lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        m
    };
    static ref COUNT: usize = HASHMAP.len();
    static ref NUMBER: u32 = times_two(21);
}

fn times_two(n: u32) -> u32 { n * 2 }

fn main() {
    println!("The map has {} entries.", *COUNT);
    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());
    println!("A expensive calculation on a static results in: {}.", *NUMBER);
}

Обратите внимание, что autoderef означает, что вам даже не нужно использовать * всякий раз, когда вы вызываете метод для вашей статической переменной. Переменная будет инициализирована в первый раз, когда она Deref 'd.

Однако lazy_static переменные неизменяемы (поскольку они находятся за ссылкой). Если вы хотите изменить статичность, вам нужно будет использовать Mutex:

lazy_static! {
    static ref VALUE: Mutex<u64>;
}

impl Drop for IsFoo {
    fn drop(&mut self) {
        let mut value = VALUE.lock().unwrap();
        *value += 1;
    }
}

#[test]
fn test_drops_actually_work() {
    // Have to drop the mutex guard to unlock, so we put it in its own scope
    {
        *VALUE.lock().unwrap() = 0;
    }
    {
        let c = CBox;
        c.set(IsFoo);
        c.set(IsFoo);
        c.poll(/*...*/);
    }
    assert!(*VALUE.lock().unwrap() == 2); // Assert that all expected drops were invoked
}
11
ответ дан Shepmaster 19 August 2018 в 16:27
поделиться
Другие вопросы по тегам:

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