2009-09-10 2 views
4

У меня есть код, который я хочу реорганизовать. У меня есть много методов, которые принимают несколько аргументов одного типа, например:Обтекание булевых объектов в объектах

public void foo(String name, String street, boolean b1, boolean b2) { ... } 

и так далее. Поскольку разные объекты могут различаться только по имени, я хотел бы их обернуть в Object (Enums), чтобы я мог использовать тип системы языка (Java в этом случае).

public class Name { 
    private String value; 
    public String getValue() { return value; } 
    // ... 
} 

Нравится программа? Поделись с друзьями! Это будет гарантировать, что он не будет случайно перепутать порядок параметров методы и, таким образом, не производит неожиданное поведение во время выполнения:

foo(new Name("John"), new Street("Broadway"), new B1(true), new B2(false); 

Это делает рефакторинга намного безопаснее, вы можете нести объект через система, если вы хотите, данные внутри нее, строка всегда безопасна. Только когда вам это нужно, вы получите его, вызвав getValue().

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

Но как насчет логических оберток? Это либо ИСТИНА, либо ЛОЖЬ. Реализация выглядит просто, ну, немного смешно:

public enum Quanto { 

    YES() { 
     protected boolean isQuanto() { 
      return true; 
     } 
    }, 
    NO() { 
     protected boolean isQuanto() { 
      return false; 
     } 
    }; 

    protected abstract boolean isQuanto(); 

} 

Даже незнакомец я считаю, что вызывающий код выглядит следующим образом:

public void doStuff(Quanto quanto) { 
    if(quanto.isQuanto()) { 
     // ... 
    } 
} 

Технически это не имеет значения, конечно, но это просто не чувствую себя хорошо ... Вы нашли «лучшие» способы борьбы с этим?

EDIT: Что же неугодно меня является тот факт, что есть больше значения, чем мыслимое ДА и NO в приведенном выше примере, скажем MayBe ...?!

Спасибо!

+0

Ваш код делает это из этого анти-шаблона: http://www.martinfowler.com/bliki/AnemicDomainModel.html – SteveD

+1

В принципе, он очень процедурный и не очень объектно-ориентированный. – SteveD

+0

Это не обязательно плохо ... – me22

ответ

9

Я бы обернул булевы в семантические перечисления. Другими слова:

public void doStuff(boolean isActive, boolean wrapResult); 

становится

public enum State {ACTIVE, INACTIVE}; 
public enum ResultMode {WRAPPED, UNWRAPPED}; 

public void doStuff(State state, ResultMode resultsMode); 
+1

Это. Чистый, легкий, лаконичный. – CPerkins

+0

Да. Но это именно то, что я предложил, не так ли? Вы просто оставляете метод isQuanto и имеете код клиента, если (q == Quanto.YES) ... – raoulsson

+0

IMO 'doStuff (State.ACTIVE, Mode.UNWRAPPED)' выглядит более естественным и легче понять, чем ' doStuff (Active.YES, Wrapped.NO) '. – ChssPly76

1

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

public class Encapsulator { 

    private boolean isSelected; 
    private boolean isAwake; 


    public boolean isAwake() { 
     return isAwake; 
    } 

    public void setIsAwake(boolean isAwake) { 
     this.isAwake = isAwake; 
    } 

    public boolean isSelected() { 
     return isSelected; 
    } 

    public void setIsSelected(boolean isSelected) { 
     this.isSelected = isSelected; 
    } 
} 

Таким образом, когда вы получаете доступ к данным он очень ясно, что конкретный элемент в объекте делает одну вещь или другой. Он также уменьшает набор параметров для методов, который является запахом кода в соответствии с Мартином Фаулером.

+0

Мне лично нравится параметрическая связь. Конечно, вы можете превратить это в беспорядок, но, предпочитая дополнительный параметр над какой-то другой конструкцией (особенно если это связано с добавлением дополнительного класса), часто получается лучшее решение IMHO. – eljenso

+0

Проблема заключается в том, что у вас много параметров, которые передаются, - вот что шаблон предназначен для решения. Если есть только 2 или 3 (может быть, даже 4), или они передаются только один раз, это совсем другая ситуация. :) – aperkins

4

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

Сайт вызов будет выглядеть примерно так:

foo(new foo_arguments().Name("John").Street("Broadway").B1(true).B2(false)); 

И тогда вы будете использовать arguments.Name() и такие внутри функции.

Это имеет дополнительное преимущество, что позволяет дать аргументы по умолчанию без огромного количества перегрузок и позволяет аргументы быть указаны в любом порядке, так это работает:

foo(new foo_arguments().Street("Sesame").Name("Monster")); 

Требуемый класс:

public class foo_arguments { 
    private string _name = "John Doe"; 
    public foo_arguments Name(string name) { _name = name; return this; } 
    public string Name() { return _name; } 

    private string _street = "Pennsylvania Ave NW"; 
    public foo_arguments Street(string street) { _street = street; return this; } 
    public string Street() { return _street; } 

    private string _b1 = false; 
    public foo_arguments B1(string b1) { _b1 = b1; return this; } 
    public boolean B1() { return _b1; } 

    private string _b2 = true; 
    public foo_arguments B2(string b2) { _b2 = b2; return this; } 
    public boolean B2() { return _b2; } 
} 

Как в стороне, на C# вы можете сделать это действительно элегантно с авто-свойствами и инициализаторами объектов.

+0

В зависимости от того, как выглядит исходный код, можно надеяться, что можно идентифицировать один или несколько объектов, что имеет смысл более глубоким образом, чем, скажем, foo_arguments. Я не знаю, что делают логики в приведенном выше примере, но, возможно, у вас может быть класс Person, содержащий имя, улицу, b1 и b2. Попытайтесь определить, какие объекты вы хотите иметь, вместо передачи примитивов. – Buhb

2

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

Я бы не стал инкапсулировать один Boolean в один объект. Для меня это не кажется правильным.

Смежные вопросы