dlidstrom/MinaGlosor

Organisera klasserna i domänen bättre

Opened this issue · 2 comments

Dom behöver grupperas per modell. Använd följande för att hantera konverteringar: https://ravendb.net/docs/article-page/3.5/Csharp/client-api/listeners/what-are-conversion-listeners-and-how-to-work-with-them

Man kan också ändra namespace genom Newtonsoft.json, så här: http://stackoverflow.com/questions/9908913/handling-namespace-changes-with-typenamehandling-all

Events, Commands, Queries, Tasks kan få gemensamma basklasser (per domänmodell). Då skulle det bli lättare att organisera var alla Events ska hanteras (samma AbstractHandle blir lätt att styra genom att införa typning på Handle på ovanstående basklass). Kolla på http://pastebin.com/EEdvVh2R för att göra det här. En CommandModel med flera generiska parametrar som styr vilka Handle man måste implementera.

Gör metatester för alla events så att t.ex. events från WordScore alltid har Id, WordId, OwnerId som första parametrar. Eventsen ska ligga i samma namespace, det är så man hittar dom för testerna.

Skapa ett "fingerprint" för klasserna i domänen. Spara denna i databasen. Vid start kan man kolla så att fingerprint stämmer. Gör den inte det så får man migrera databasen i ett admin-steg.

Utforska idéerna här:

void Main()
{
    var user = new User();
    user.Handle(new ActivateUserCommand(12));
    user.Handle(new InactivateUserCommand(12));
}

// Define other methods and classes here
public interface DomainModel
{
    int Id { get; }
}

public class User : UserEvents.Model, UserCommands.Model, DomainModel
{
    public int Id { get; private set; }

    public void Handle(ActivateUserCommand command)
    {
        command.UserId.Dump("ActivateUserCommand");
        Raise(new UserActivatedEvent(command.UserId));
    }

    public void Handle(InactivateUserCommand command)
    {
        command.UserId.Dump("InactivateUserCommand");
        Raise(new UserInactivatedEvent(command.UserId));
    }

    public void Handle(EnableUserCommand command)
    {
    }
}

public class ActivateUserCommand
{
    public ActivateUserCommand(int userId)
    {
        UserId = userId;
    }

    public int UserId { get; private set; }
}

public class InactivateUserCommand
{
    public InactivateUserCommand(int userId)
    {
        UserId = userId;
    }

    public int UserId { get; private set; }
}

public class EnableUserCommand
{
    public EnableUserCommand(int userId)
    {
        UserId = userId;
    }

    public int UserId { get; private set; }
}

public abstract class UserCommands : CommandUnion<User, ActivateUserCommand, InactivateUserCommand, EnableUserCommand>
{
}

public interface CommandUnion
{
}

public abstract class CommandUnion<TModel, TCommand> : CommandUnion where TModel : DomainModel
{
    public interface Model
    {
        void Handle(TCommand command);
    }
}

public abstract class CommandUnion<TModel, TCommand1, TCommand2> where TModel : DomainModel
{
    public interface Model
    {
        void Handle(TCommand1 command);

        void Handle(TCommand2 command);
    }
}

public abstract class CommandUnion<TModel, TCommand1, TCommand2, TCommand3> where TModel : DomainModel
{
    public interface Model
    {
        void Handle(TCommand1 command);

        void Handle(TCommand2 command);

        void Handle(TCommand3 command);
    }
}

public abstract class EventUnion
{
    public abstract class BaseModel
    {
        protected void DoRaise<TEvent>(TEvent @event)
        {
            Console.WriteLine("Raising " + @event.GetType().ToString());
        }
    }
}

public abstract class EventUnion<TEvent> : EventUnion
{
    public abstract class Model : EventUnion.BaseModel
    {
        protected void Raise(TEvent @event)
        {
            DoRaise(@event);
        }
    }
}

public abstract class EventUnion<TEvent1, TEvent2> : EventUnion
{
    public abstract class Model : EventUnion.BaseModel
    {
        protected void Raise(TEvent1 @event)
        {
            DoRaise(@event);
        }

        protected void Raise(TEvent2 @event)
        {
            DoRaise(@event);
        }
    }
}

public class UserActivatedEvent
{
    public UserActivatedEvent(int userId)
    {
        UserId = userId;
    }

    public int UserId { get; private set; }
}

public class UserInactivatedEvent
{
    public UserInactivatedEvent(int userId)
    {
        UserId = userId;
    }

    public int UserId { get; private set; }
}

public abstract class UserEvents : EventUnion<UserActivatedEvent, UserInactivatedEvent>
{
}

Utforska detta också (model => logic => events):

void Main()
{
    var model = new
    {
        age = 20
    };
    var logic = Logic.With(() => model).Sequence(
        m => new { age2 = m.age },
        Logic.With(() => model).If(
            m => m.age < 20,
            Logic.Raise(() => new MyEvent("Less than 20"))
        ),
        Logic.With(() => model).If(
            m => m.age >= 20,
            Logic.Raise(() => new MyEvent("Greater than or equal to 20"))
        )
    );

    var wordScore = new WordScore();
    wordScore.UpdateConfidence(2);
}

public class WordScore
{
    public WordScore()
    {
        Score = 2.5;
    }

    public double Score { get; private set; }

    public void UpdateConfidence(int confidenceLevel)
    {
        var logic = Sequence(
            new { score = Score, confidenceLevel },
            m => Tuple.Create(
                If(m,
                   im => im.confidenceLevel < 3,
                   im => Raise(() => new ScoreChangedEvent(im.score * im.confidenceLevel))),
                If(m,
                   im => im.confidenceLevel >= 3,
                   im => Raise(() => new ScoreChangedEvent(10 * im.score * im.confidenceLevel)))));
        logic.Run();
    }

    private Logic If<TIfModel>(TIfModel ifModel, Func<TIfModel, bool> predicate, Func<TIfModel, Logic> trueBranch)
    {
        return new IfImpl<TIfModel>(ifModel);
    }

    private Logic Sequence<TSequenceModel>(TSequenceModel sequenceModel, Func<TSequenceModel, Logic> sequenceItemFactory)
    {
        return new SequenceImpl<TSequenceModel>(sequenceModel, sequenceItemFactory);
    }

    private Logic Sequence<TSequenceModel>(TSequenceModel sequenceModel, Func<TSequenceModel, Tuple<Logic, Logic>> sequenceItemsFactory)
    {
        return new SequenceImpl<TSequenceModel>(sequenceModel, sequenceItemsFactory);
    }

    private Logic Raise(Func<object> eventFactory)
    {
        return new RaiseImpl(eventFactory);
    }

    private interface Logic
    {
        void Run();
    }

    private class RaiseImpl : Logic
    {
        public RaiseImpl(Func<object> eventFactory)
        {
            EventFactory = eventFactory;
        }

        public Func<object> EventFactory { get; private set; }

        public void Run()
        {
            Console.WriteLine(EventFactory.Invoke());
        }
    }

    private class IfImpl<TIfModel> : Logic
    {
        public IfImpl(TIfModel ifModel)
        {
        }

        public void Run()
        {
            Console.WriteLine("Inside IfImpl");
        }
    }

    private class SequenceImpl<TSequenceModel> : Logic
    {
        private readonly TSequenceModel model;
        private readonly Func<TSequenceModel, Logic[]> sequenceItemFactory;

        public SequenceImpl(TSequenceModel model, Func<TSequenceModel, Logic> sequenceItemFactory)
        {
            this.model = model;
            this.sequenceItemFactory = m => new[] { sequenceItemFactory.Invoke(m) };
        }

        public SequenceImpl(TSequenceModel model, Func<TSequenceModel, Tuple<Logic, Logic>> sequenceItemFactory)
        {
            this.model = model;
            this.sequenceItemFactory = m =>
            {
                var tuple = sequenceItemFactory.Invoke(m);
                return new[] { tuple.Item1, tuple.Item2 };
            };
        }

        public void Run()
        {
            var sequenceItems = this.sequenceItemFactory.Invoke(this.model);
            foreach (var sequenceItem in sequenceItems)
                sequenceItem.Run();
        }
    }

    private class SequenceImpl<TSequenceModel, TLogic1, TLogic2> : Logic
    {
        public SequenceImpl(TSequenceModel model, Func<TSequenceModel, Tuple<TLogic1, TLogic2>> sequenceItemsFactory)
        {
        }

        public void Run()
        {
        }
    }

    private class ScoreChangedEvent
    {
        public ScoreChangedEvent(double newScore)
        {
            NewScore = newScore;
        }

        public double NewScore { get; private set; }
    }
}

// Define other methods and classes here
public abstract class Logic
{
    public static ModelHolder<TModel> With<TModel>(Func<TModel> modelFunc)
    {
        return new ModelHolder<TModel>(modelFunc);
    }

    public static Logic Raise(Func<IEvent> raiseFunc)
    {
        return new RaiseImpl(raiseFunc);
    }
}

public class ModelHolder<TModel>
{
    private readonly Func<TModel> modelFunc;

    public ModelHolder(Func<TModel> modelFunc)
    {
        this.modelFunc = modelFunc;
    }

    public Logic Sequence<TModelSubset>(Func<TModel, TModelSubset> modelFunc, params Logic[] steps)
    {
        return new SequenceImpl<TModelSubset>(modelFunc.Invoke(this.modelFunc.Invoke()), steps);
    }

    public Logic If(Func<TModel, bool> expr, Logic then)
    {
        return new IfElseImpl();
    }
}

public class SequenceImpl<TModel> : Logic
{
    private readonly TModel model;
    private readonly Logic[] steps;

    public SequenceImpl(TModel model, Logic[] steps)
    {
        this.model = model;
        this.steps = steps;
    }
}

public class IfElseImpl : Logic
{
}

public class RaiseImpl : Logic
{
    public RaiseImpl(Func<IEvent> raiseFunc)
    {
    }
}

public interface IEvent
{
}

public class MyEvent : IEvent
{
    private readonly string message;

    public MyEvent(string message)
    {
        this.message = message;
    }
}