简体   繁体   中英

Design Pattern - Fat adapter

We've implemented the adapter design pattern whose job is the following:

  1. Act as a liaison between service and data access layers.
  2. Convert raw data (from data source, internal or external) to domain specific data. Do necessary validation and massaging.
  3. Sometimes, making the DAO calls may depend on data not readily available from input parameters or additional service calls may need to be made based on input data. In other words, the adapter can't always do a 1:1 mapping between the service and the DAO. It may map the same call from service to different DAO calls based on the input parameters.

Item #3 is starting to worry me as the adapters are becoming more complicated than I'd originally imagined. I'm not aware of a design pattern to trim down an adapter. Is there one? Suggestions?

You've used what I like to call the "swiss army knife" pattern.

Best practice says you should break up your class into at least 3 classes, one for each concern.

Instead of using an adapter or a full Repository(CRUD operations), i would use an IReader interface for reading and visitor pattern for insert update delete, so you can separate domain logic from infraestructure(persistance) details, Here is the idea:

public class MyBusinessObject : IAcceptBusinessVisitor, IAcceptMyBusinessIdVisitor
{
    private readonly string _id;

    private string MyPrivateProp { get; set; }
    //Fully encapsulated object
    public MyBusinessObject(string id, string myPrivateProp)
    {
        _id = id;
        MyPrivateProp = myPrivateProp;
    }

    public void UpdateMyProp(string newProp)
    {            
        if (string.IsNullOrWhiteSpace(newProp)) throw new ArgumentNullException(nameof(newProp));
        //Business rules ...
        MyPrivateProp = newProp;
    }

    public void Accept(IMyBusinessObjectVisitor visitor)
    {
        if (visitor == null) throw new ArgumentNullException(nameof(visitor));
        visitor.Visit(_id, MyPrivateProp);
    }

    public void Accept(IMyBusinessIdVisitor visitor)
    {
        if (visitor == null) throw new ArgumentNullException(nameof(visitor));
        visitor.Visit(_id);
    }
}

public interface IAcceptBusinessVisitor
{
    void Accept(IMyBusinessObjectVisitor visitor);
}

public interface IAcceptMyBusinessIdVisitor
{
    void Accept(IMyBusinessIdVisitor visitor);
}

public interface IMyBusinessObjectVisitor
{
    void Visit(string id, string prop);
}

public interface IMyBusinessIdVisitor
{
    void Visit(string id);
}

public class SavePersistanceVitor : IMyBusinessObjectVisitor
{
    public void Visit(string id, string prop)
    {
        //Save to Database
    }
}

public class UpdatePersistanceVitor : IMyBusinessObjectVisitor
{
    public void Visit(string id, string prop)
    {
        //Update to Database
    }
}

public class DeleteVitor : IMyBusinessIdVisitor
{
    public void Visit(string id)
    {
        //Delete in Database
    }
}

Here for Reading:

public interface IMyBusinessObjectReader
{
    MyBusinessObject Read(string id);
}

class MyBusinessObjectReaderFromDb : IMyBusinessObjectReader
{
    public MyBusinessObject Read(string id)
    {
        //Read from database
        string myPrivateProp = "";
        return new MyBusinessObject(id, myPrivateProp);
    }
}

the next step could be adding generics for reading and the visitors. In this case you end up having little tiny classes and gain flexibility and the benefits of solid principles like single responsability, interface segregation, etc. So you can create a rich encapsulated domain and extend its functionality with some desing principles. Regards!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM