Подтвердить что ты не робот

Создание API, которое свободно

Как можно создать API, который свободно владеет природой?

Используется ли это с помощью методов расширения?

4b9b3361

Ответ 1

Эта статья объясняет это намного лучше, чем я когда-либо мог.

РЕДАКТИРОВАТЬ, не могу сжать это в комментарии...

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

Как говорит Мартин Фаулер в оригинальной статье о плавных интерфейсах:

Возможно, самое важное для уведомление об этом стиле заключается в том, что намерение сделать что-то по линии внутреннего DomainSpecificLanguage. Действительно, это почему мы выбрали термин "свободно" описать это, во многом термины - синонимы. API в первую очередь предназначенные для чтения и течь. Цена этого бега больше усилий, как в мышлении, так и в самой конструкции API. простой API конструктора, сеттера и методы добавления намного проще написать. Прибытие с хорошей беглостью API требует хорошей мысли.

Как и в большинстве случаев API создаются один раз и используются снова и снова, дополнительные усилия могут стоить того.

И многословный? Я все для многословия, если он служит читабельности программы.

Ответ 2

MrBlah,

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

Ниже вы увидите пример кода, который я создал в другом потоке

public class Coffee
{
    private bool _cream;
    private int _ounces;

    public static Coffee Make { get { return new Coffee(); } }

    public Coffee WithCream()
    {
        _cream = true;
        return this;
    }
    public Coffee WithOuncesToServe(int ounces)
    {
        _ounces = ounces;
        return this;
    }
}

var myMorningCoffee = Coffee.Make.WithCream().WithOuncesToServe(16);

Ответ 3

В то время как многие люди ссылаются на Мартина Фаулера как видного представителя в текущем обсуждении API, его ранние заявки на дизайн фактически развиваются вокруг цепочка методов. Свободные API могут быть дополнительно развиты в фактические внутренние языки, специфичные для домена. Здесь можно увидеть статью, в которой объясняется, как обозначение BNF грамматики можно вручную преобразовать в" свободный API":

http://blog.jooq.org/2012/01/05/the-java-fluent-api-designer-crash-course/

Он преобразует эту грамматику:

enter image description here

В этот Java API:

// Initial interface, entry point of the DSL
interface Start {
  End singleWord();
  End parameterisedWord(String parameter);
  Intermediate1 word1();
  Intermediate2 word2();
  Intermediate3 word3();
}

// Terminating interface, might also contain methods like execute();
interface End {
  void end();
}

// Intermediate DSL "step" extending the interface that is returned
// by optionalWord(), to make that method "optional"
interface Intermediate1 extends End {
  End optionalWord();
}

// Intermediate DSL "step" providing several choices (similar to Start)
interface Intermediate2 {
  End wordChoiceA();
  End wordChoiceB();
}

// Intermediate interface returning itself on word3(), in order to allow
// for repetitions. Repetitions can be ended any time because this 
// interface extends End
interface Intermediate3 extends End {
  Intermediate3 word3();
}

Java и С# несколько похожи, пример, безусловно, переводится и в ваш прецедент. Вышеупомянутая методика была в значительной степени использована в jOOQ, свободно владеющем API/внутренним доменным языком, моделирующим язык SQL в Java

Ответ 4

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

Первоначальное мышление, касающееся "беглости", похоже, было в основном о добавлении силы и гибкости (цепочка методов и т.д.) к объектам, делая код более понятным.

Например

Company a = new Company("Calamaz Holding Corp");
Person p = new Person("Clapper", 113, 24, "Frank");
Company c = new Company(a, 'Floridex', p, 1973);

менее "бегло", чем

Company c = new Company().Set
    .Name("Floridex");
    .Manager(
        new Person().Set.FirstName("Frank").LastName("Clapper").Awards(24)
    )
    .YearFounded(1973)
    .ParentCompany(
        new Company().Set.Name("Calamaz Holding Corp")
    )
;

Но для меня более поздняя версия на самом деле не является более сильной или гибкой, чем

Company c = new Company(){
   Name = "Floridex",
   Manager = new Person(){ FirstName="Frank", LastName="Clapper", Awards=24 },
   YearFounded = 1973,
   ParentCompany = new Company(){ Name="Calamaz Holding Corp." }
};

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

1 - Стоимость, связанная с созданием и поддержанием слоев объектов (независимо от того, кто это делает), является столь же реальной, актуальной и важной, как затраты, связанные с созданием и поддержкой кода, который их потребляет.

2 - Наложение кода, встроенное в слои объектов, создает столько же (если не больше) проблем, как разбухание кода в коде, который потребляет эти объекты.

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

Чтобы не сказать, что я не чувствую, что нет места для цепочки методов. Мне очень нравится иметь возможность делать такие вещи, как (в JavaScript)

var _this = this;
Ajax.Call({
    url: '/service/getproduct',
    parameters: {productId: productId},
)
.Done(
    function(product){
        _this.showProduct(product);
    }
)
.Fail(
    function(error){
        _this.presentError(error);
    }
);

.. где (в гипотетическом случае, который я представляю) Done and Fail были дополнениями к исходному объекту Ajax и были добавлены без изменения какого-либо исходного объектного кода Ajax или любого существующего кода, который сделал использование исходного объекта Ajax и без создания одноразовых вещей, которые были исключениями для общей организации кода.

Итак, я определенно нашел значение при создании подмножества функций объекта, возвращающего объект 'this'. Фактически всякий раз, когда у меня есть функция, которая в противном случае вернула бы пустоту, я считаю, что она возвращает это.

Но я еще не нашел существенной ценности при добавлении "свободного интерфейса" (.eg "Set" ) к объекту, хотя теоретически кажется, что может существовать какая-то организация, похожая на пространство имен, которая может возникнуть практики этого, что может быть целесообразным. ( "Set" может быть не особенно ценным, но "Command", "Query" и "Transfer" могут, если это помогло организовать вещи, облегчить и минимизировать влияние дополнений и изменений.) Одно из потенциальных преимуществ такой практики, в зависимости от того, как это было сделано, могло бы быть улучшение типичного уровня кодера и внимания к уровням защиты - недостаток которых, несомненно, вызвал большой объем печали.

Ответ 5

KISS: Держите его просто глупым.

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

Даже если вы думаете, что "каждый может использовать этот API, потому что он использует все различные типы методологии". По правде говоря, пользователь начнет чувствовать себя потерянным, потому что вы постоянно меняете структуру/структуру данных API на новый принцип дизайна или соглашение об именах.

Если вы хотите изменить на полпути к другому принципу дизайна, например.. Преобразование из кодов ошибок в обработку исключений, потому что некоторые более высокие командные мощности. Это было бы глупостью и обычно в хвосте было бы больно. Лучше остаться на курсе и добавить функциональность, которую ваши клиенты могут использовать и продавать, а не заставлять их повторно писать и снова открывать все свои проблемы.

Следуя вышеизложенному, вы можете видеть, что написание Fluent API больше, чем на глаза. Есть психологический и эстетический выбор, который нужно сделать, прежде чем начинать писать, и даже тогда чувство, потребность и желание соответствовать требованиям клиентов и оставаться последовательными - это самое сложное.

Ответ 6

Что такое свободный API

Википедия определяет их здесь http://en.wikipedia.org/wiki/Fluent_interface

Почему бы не использовать свободный интерфейс

Я бы предложил не внедрять традиционный свободный интерфейс, так как он увеличивает объем кода, который вам нужно написать, усложняет ваш код и просто добавляет ненужный шаблон.

Другой вариант, ничего не делайте!

Не реализуйте ничего. Не предоставляйте "простые" конструкторы для настройки свойств и не предоставляйте умный интерфейс, чтобы помочь вашему клиенту. Разрешить клиенту устанавливать свойства, как обычно. В .Net С# или VB это может быть так же просто, как использовать инициализаторы объектов.

Car myCar = new Car { Name = "Chevrolet Corvette", Color = Color.Yellow };

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

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

CarConfig conf = new CarConfig { Color = Color.Yellow, Fabric = Fabric.Leather };
Car myCar = new Car { Config = conf };

Ответ 8

Написание свободного API сложно, поэтому я написал Diezel, который является Fluent API-генератором для Java. Он генерирует API с интерфейсами (или курсом):

  • управлять вызывающим потоком
  • улавливать общие типы (например, guice one)

Он также генерирует реализации.

Это плагин maven.

Ответ 9

Нет и да. Основы - хороший интерфейс или интерфейсы для типов, которые вы хотите вести свободно. Библиотеки с методами расширения могут расширить это поведение и вернуть интерфейс. Методы расширения предоставляют другим возможность расширить ваш свободный API с помощью большего количества методов.

Хорошая плавная конструкция может быть трудной и требует довольно длительного периода проб и ошибок, чтобы полностью очертить основные строительные блоки. Просто свободный API для настройки или настройки не так уж тяжело.

Обучение созданию свободного API делает это, глядя на существующие API. Сравните FluentNHibernate с плавными API-интерфейсами .NET или свободными интерфейсами ICriteria. Многие API-интерфейсы конфигурации также разработаны "плавно".