Frage Wie Hinzufügen von Geschäftslogik zu dem Domäne-Dienst in Domäne-Driven-Design?


in meinem Projekt, die Business-Logik alle im Application Service, Domain-Service nur einige Entität, wer kann mir sagen oder geben Sie mir ein Beispiel zu zeigen, wie Business-Logik zum Domain-Service in Domain-Driven-Design hinzufügen? vielen Dank!

AKTUALISIEREN

Ich schreibe eine einfache Lösung, diese Lösung ist ein Abstimmungssystem, der Hauptteil der Lösung ist:

enter image description here

Vote.Application.Service.VoteService.cs:

namespace Vote.Application.Service
{
    public class VoteService
    {
        private IVoteRepository _voteRepository;
        private IArticleRepository _articleRepository;

        public VoteService(IVoteRepository voteRepository,IArticleRepository articleRepository)
        {
            _voteRepository = voteRepository;
            _articleRepository = articleRepository;
        }

        public bool AddVote(int articleId, string ip)
        {
            var article = _articleRepository.Single(articleId);
            if (article == null)
            {
                throw new Exception("this article not exist!");
            }
            else
            {
                article.VoteCount++;
            }

            if (IsRepeat(ip, articleId))
                return false;

            if (IsOvertakeTodayVoteCountLimit(ip))
                return false;

            _voteRepository.Add(new VoteRecord()
            {
                ArticleID = articleId,
                IP = ip,
                VoteTime = DateTime.Now
            });

            try
            {
                _voteRepository.UnitOfWork.Commit();
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private bool IsRepeat(string ip, int articleId)
        {
            //An IP per article up to cast 1 votes
            //todo
            return false;
        }

        private bool IsOvertakeTodayVoteCountLimit(string ip)
        {
            //An IP per day up to cast 10 votes
            //todo
            return false;
        }
    }
}

Vote.Domain.Contract.IVoteRepository.cs:

namespace Vote.Domain.Contract
{
    public interface IVoteRepository
        : IRepository<VoteRecord>
    {
        void Add(VoteRecord model);
    }
}

Vote.Domain.Contract.IArticleRepository.cs:

namespace Vote.Domain.Contract
{
    public interface IArticleRepository
        : IRepository<Article>
    {
        void Add(VoteRecord model);

        Article Single(int articleId);
    }
}

Vote.Domain.Entities.VoteRecord:

namespace Vote.Domain.Entities
{
    public class VoteRecord
    {
        public int ID { get; set; }

        public DateTime VoteTime { get; set; }

        public int ArticleID { get; set; }

        public string IP { get; set; }
    }
}

Vote.Domain.Entities.Article:

namespace Vote.Domain.Entities
{
    public class Article
    {
        public int ID { get; set; }

        public string Title { get; set; }

        public string Content { get; set; }

        public int VoteCount { get; set; }
    }
}

Ich möchte die Business-Anmeldung in application.service zu Domain.service (momentan nicht dieses Projekt) verschieben, wer kann mir helfen? vielen Dank!


6
2017-08-16 05:21


Ursprung


Antworten:


DDD konzentriert sich darauf, Domänenmodelle so zu gestalten, dass sie der Anforderung entsprechen. Das Schema in der Datenbank spielt keine große Rolle.

Wenn Ihre Domain Entity nur Eigentum Tasche ist, scheint Sie die Anemic Model Anti-Muster. Geschäftslogik sollte in Domain-Entitäten sein. Also, in Ihrem Fall, um zu vermeiden, Business-Logik zu Application Service undicht. Sie können ein neues Modell mit dem Namen Client haben, um zum Beispiel IP oder andere Eigenschaften zu speichern.

Um das Verständnis zu erleichtern, sollte diese Methode in der Klasse Client sein, unabhängig davon, ob der Client die Grenzwerte am Tag überschreitet. Ähnlich wie bei der Methode IsRepeated.

Also, Ihr Domain-Objekt sollte sein:

public class Client
{
    public string Ip { get; set; }
    // More properties if needed

    public List<Vote> Votes { get; set; }

    public bool ExceedLimitInDay()
    {
    }
}

public class Vote
{ 
    public int Id { get; set; } 
    public DateTime VoteTime { get; set; } 
    public Article Article { get; set; } 
    public Client { get; set; } 
}

public class Article   
{   
    public int Id { get; set; }   
    public string Title { get; set; }   
    public string Content { get; set; }   

    public List<Vote> Votes { get; set; }

    public bool IsRepeated(string ip)
    {
        return Votes.Select(v => v.Client.Ip == ip).Any();      
    }
} 

Hinweis: Wenn Sie keinen neuen Tabellenclient erstellen müssen, ordnen Sie ihn einfach der Tabelle "Abstimmen" zu. Wie bei den VoteCount-Eigenschaften ist es unnötig, weil Sie es können Anzahl basierend auf der Liste der Abstimmungen


7
2017-08-16 10:32



Ich denke, Abstimmung und Artikel sind ein Aggregat. Ich weiß nicht viel über Ihre Domain, aber ich gehe davon aus, dass jede Abstimmung nur für einen bestimmten Artikel wichtig ist. Stimmen werden nicht über Artikel verteilt, sodass sie als Mitglieder der Aggregation behandelt und nicht als Entitäten der gesamten Domäne behandelt werden.

Meiner Meinung nach wäre Artikel die root-Entity des Aggregates und Vote wäre eine Member-Entity innerhalb. Wenn Sie dieses "Muster" anwenden, können Sie die gesamte Geschäftslogik darin einbetten.

Sie könnten eine AddVote (...) in Ihrem Artikel oder eine Geschäftslogik wie diese haben.

Dann könnten Sie sich fragen .. "Ok ... aber was ist mit Persistenz?". Da Sie Ihre Artikelabstimmung als ein Aggregat definieren, würden Sie sie dann zusammen behandeln. Wenn Sie CRUD-Vorgänge für einen Artikel ausführen, führen Sie diese Vorgänge gleichzeitig in den Aggregierten Mitgliedern (Abstimmungen) aus. Sie benötigen also möglicherweise ein Repository für das ArticleAggregate, es wird sich um die Votes des Artikels kümmern.

Hoffe, das macht Sinn für dich. Wählen Sie die beste Option abhängig von Ihrer Domain.


1
2017-08-23 14:46



Von einem Blick auf den Application Service würde ich sagen, es ist kaum ein Application Service, es ist schon ein bisschen ein Domain Service in dem Sinne, dass es einige Domain Logik erfasst (im Gegensatz zu Viewmodel Input und Mapping auf Entitäten). Sie haben jedoch größere Probleme:

Deine Aggregate sind ausgeschaltet. Sie wollen zwei Invarianten um eine IP-Adresse erzwingen, die einen Artikel abstimmen (eine IP kann nur einmal pro Artikel abstimmen, eine IP kann bis zu 10 Stimmen pro Tag abgeben). Keine Substantive passen gut dazu (Artikel, Abstimmung), dies zu verfolgen.

ArticleVotes sind möglicherweise gut geeignet, um die von einem ips für einen Artikel abgegebenen Stimmen zu verfolgen und durchzusetzen, während IPVotesPerDate die Anzahl der von einer einzelnen IP-Adresse pro Tag abgegebenen Stimmen verfolgen kann. Sie können ArticleVotes möglicherweise in das Artikelaggregat verschieben, wenn die Gesamtzahl der Stimmen niedrig genug ist (und Sie können die Leistung dort belassen, wo Sie sie haben möchten). IPVotesPerDate könnte in VotesPerDate umgewandelt werden, wenn die Gesamtanzahl der IPs, die täglich gewählt werden, niedrig ist.

Unter dem Strich werden die IP und das Abstimmungsvolumen die Leistung Ihrer Aggregate diktieren. Dies könnte dazu führen, dass Sie sie umgestalten müssen, um die von Ihnen gewünschten Leistungswerte zu berücksichtigen. Am besten ist es, diese Zahlen zu finden, um zu wissen, in welche Richtung man gehen soll.

Von da an sollte es offensichtlich sein, dass das gewünschte Verhalten in die genannten Aggregate eingebracht werden konnte. Daher könnte die Notwendigkeit eines Domain-Service wegfallen. Ich sage vielleicht, weil der Anwendungsfall immer noch eine IP ist, die über einen Artikel abstimmt. Als solche, die eine gewisse Koordination über Aggregate erfordern, ergo ergo die Einführung eines Domain-Service.


0
2017-08-22 22:29