ООП: Имеете логику «действия» для «сущности» в одном классе, но вызываете ее в другом? - PullRequest
0 голосов
/ 11 мая 2018

Настройка структуры AI. Я сразу же столкнулся с проблемой в моем интерфейсе, извините за посредственные комментарии:

//Probability is just a class I've made to represent (you guessed it) probability

public interface IAction
{
    /// <summary>
    /// Returns a Dictionary of possible future states of the IEntity parameter and their estimated probability
    /// </summary>
    Dictionary<IEntity, Probability> EstimatePossibleOutcomeSpectrum(IEntity entity);
    /// <summary>
    /// Have the IEntity parameter "do" this action
    /// </summary>
    void Do(IEntity entity);
}

public interface IEntity
{
}

Проблема в том, что здравый смысл диктует, что сущность выполняет действия, а не наоборот, очевидно, я могу переименовать метод, чтобы он имел грамматический смысл, но в конечном итоге я бы хотел переместить «делать» в IEntity, но потом, когда что касается реализации интерфейсов, я понятия не имею, как заставить «сущность» выполнить «действие», не просто «передав эстафету», имея что-то вроде:

public class EntityExample
{
    /// <summary>
    /// Returns a Dictionary of estimated future states after "doing" the IAction parameter
    /// </summary>
    Dictionary<IEntity, Probability> EstimatePossibleOutcomeSpectrum(IAction action)
    {
        action.[Some method or a Action<Entity> call](this);
    }
    /// <summary>
    /// "do" the Action paramater
    /// </summary>
    void Do(IAction action)
    {
        action.[Some method or a Action<Entity> call](this);
    }
}

Который чувствует себя так же, если не хуже.

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

1 Ответ

0 голосов
/ 11 мая 2018

Проблема в том, что здравый смысл диктует, что сущность совершает действия, а не наоборот

Поскольку я не знаю, что такое "сущности", мой здравый смысл говоритЯ ничего не знаю о том, что сущности делают действия, или действия потребляют сущности.

И "сущность", и "действие" являются существительными в этой ситуации, поэтому я не вижу причин, по которым они не должны быть классами.

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

Не беспокойтесь о том, что является наиболее «чистым ООП» решением, особенно если это означает сделать странным,неэффективный или неэффективный код.Вера в то, что ООП является самоцелью, даже если она делает кодирование более дорогим и трудным, я называю «болезнью объектного счастья».Написание кода ООП не должно радовать вас;Эффективное использование ООП для снижения затрат и улучшения качества должно вас радовать.Если ООП не является подходящим инструментом, а функциональное программирование - функциональным.

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


Говоря о функциональном программировании, вы можете рассмотреть один из подходов - полностью перейти на функционал и представить дискретные распределения вероятностей в виде монады.

Подумайте о некоторыхдругие монады.IEnumerable<T> - это просто последовательность, возможно, пустая из T. A Nullable<T> логически совпадает с последовательностью, ограниченной ровно одним или нулем элементов.IObservable<T> - это последовательность Т, которая скорее отталкивается от вас, чем от нее.Task<T> логически является наблюдаемой, которая имеет ровно одно значение.

Не каждая монада логически является последовательностью, но вероятностные распределения .Распределение вероятностей Distribution<T> представляет собой бесконечную случайную последовательность T, выходные данные которой соответствуют определенному распределению .

Если вы пойдете по этому пути, вы обнаружите, что очень много операций естественно выпадают из операторов последовательности.Условные распределения (например, «бросьте два кубика, но отбросьте двойные») составляют всего Where.P (A | B) (вероятность A для данного B) равна Func<B, Probability<A>>, что означает, что мы можем применить оператор монадического связывания к условным вероятностям , чтобы связать условные вероятности вместе, и, таким образом, логика Байсастановится просто .И так далее.Это простая, но чрезвычайно мощная техника.

Попробуйте написать несколько реализаций

interface IDistribution<T> 
{
  T Sample();
  IDistribution<U> Bind<U>(Func<T, IDistribution<U>> f);
  // f is probability of U given a T
}

и посмотрите, к чему это приведет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...