Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
332 views
in Technique[技术] by (71.8m points)

php - How To Handle Communication Between the Domain and Database Layers?

I am fairly new to using separate layers for the business logic (Domain) and database access logic, but in the course of working things out I've come across a problem to which I still feel I haven't found a great solution.

Clarification My existing solution uses Data Mappers to deal with the database interactions directly. However, as I've further investigated this issue many people have suggested that the Domain layer should not directly communicate with nor contain the Data Mappers that actually perform the database interaction. This is why I placed the Repository objects between the Domain and the necessary Data Mappers but this doesn't feel quite natural or correct. So the real question is what layer naturally exists to handle communication between the Domain and the Data Mappers? Any examples of how to structure it would be appreciated.

For example:

  • How do I properly handle retrieving a collection of domain objects within the context of another domain object?
  • How do I force the insertion of a single domain object or collection of objects based on an action performed against another object. The case I'm facing currently is that when a Person is attached to a Campaign, then I need to insert all of the Events that need to be executed for that Person for that Campaign.
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There is a distinction between a domain model and the implementation of it. Just because your model shows a relationship Person ---> Campaign ---> Event does not mean that you have to implement it in this way. IOW, your model shows your analysis and design in an object-oriented way, yet you implement that model in OOP which is limited in how well it can replicate that model in code.

Consider the following.

A Person is not defined by its ownership of a Campaign, so campaign can be left out of its knowledge responsibities. On the other hand, a Campaign is defined by the Events that occur as part of its execution, so it is fair to have a collection of events within a campaign. The point that I am making is that each class should have just enough behaviour and knowledge to make it whole.

As for communication between the domain and the persistence layers, consider them as two very distinct systems that are not concerned with the other. All each of them knows is what its responsiblities are and what announcements it makes. For example, the persistence layer knows how to persist data passed to it and to announce that data have been saved. However, the persistence layer does not necessarily need to understand the domain objects. Similarly, the domain layer understands Person, Campaign, and Event but knows nothing about persistence.

The implication of the above is that the domain layer needs to be a whole by itself and should not be dependent on the persistence layer for its data. However, it still needs to be supplied with data to perform its responsibilities. That data can come from either the user interface or the database and is passed to it via a third-party that knows about both domain and persistence layers.

So, in code (pseudo-C#)...

namespace DomainLayer
{
    interface IDomainListener 
    {
        void PersonCreated(Person person);
    }

    class Person
    {
        private string name;

        public Person(string name)
        {
            this.name = name;
        }

        public string Name
        {
            get { return name; }
        }
    }

    class Domain 
    {
        private IDomainListener listener;

        public Domain(IDomainListener listener) {
            this.listener = listener;
        }

        public void CreatePerson(string name) {
            Person person = new Person(name);
            listener.PersonCreated(person);
        }
    }
}


namespace PersistenceLayer
{
    interface IPersistenceListener
    {
        void PersonDataSaved(int id, object data);
    }

    class Persistence
    {
        private IPersistenceListener listener;

        public Persistence(IPersistenceListener listener) 
        {
            this.listener = listener;
        }

        public void SaveData(object data)
        {
            int id = ...; // save data and return identifier
            listener.DataSaved(id, data);
        }
    }
}

namespace MyApplication
{
    class MyController : IDomainListener, IPersistenceListener
    {
        public void CreatePersonButton_Clicked()
        {
            Domain domain = new Domain(this);
            domain.CreatePerson(NameTextbox.Text);
        }

        public void PersonCreated(Person person)
        {
            Persistence persistence = new Persistence(this);
            persistence.SavePersonData(person.Name);
        }

        public void DataSaved(int id, object data)
        {
            // display data on UI
        }
    }   
}

As you can see, the namespaces represent the different tiers. The XYZListener interfaces define the announcements that are made by the XYZ tier. Any other tiers that are interested in these announcements and will respond to them need to implement these interfaces, as does our MyApplication tier.

When the "create button" is clicked, the controller creates the Domain facade object for the domain layer and registers itself as a listener. It then calls the CreatePerson method which instantiates a Person then announces that this has been done, passing the new instance. The controller responds to this announcement in the PersonCreated implementation where it spawns a facade of the persistence layer and registers itself as the listener again. It then calls the SaveData method whichannounces DataSaved when completed. The implementation of that method then displays the data on the UI.

As you can see, the domain layer and the persistence layer are each aware of only tmemselves and are not concerned with the responsibilities of the other. It is the application logic, manifested here as the controller, that wires the two together.

Back to your specific problem, you could have a method FindPerson on the persistence, which would announce PersonFound(int id). The response by the controller would be to call the persistence layer to retrieve data about campaign and events, then call the domain layer with that data to build the Person.

Sorry for the long answer...


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...