简体   繁体   中英

C# Proper solution needed for “can't specify constructor/static method in interface” problem

Okay, I need some help here.

This is the same old "can't use an interface to enforce constructors/static methods" problem.

WHAT IS THE PROPER OO DESIGN THEN??

I have a set of data entities (Entity Framework stuff) for which I wrote partial class methods to convert to/from XML (XElement objects).

I have an instance method to "save" XML:

// Convert entity to XML
public XElement ToXml() {}

...and I have a constructor to "read" XML:

// Create entity from XML constructor.
public MyEntity(XElement) {}

Alternatively, I could use a static factory method to "read" XML:

public static MyEntity ParseXml(XElement) {}

The dilemma:

  1. I could create an interface that mandates the "save" ToXml() method, but what good is that if it only addresses half the problem? An interface can't enforce either of the "load" methods.

  2. I could rely on my own good intent to create these methods without any sort of contract.

  3. I could create a static class filled with redundant methods like XmlToEntity1() and XmlToEntity2() , etc... (Now I've described a good 'generics' problem.) However, the specific conversion code (which is specific to each entity) would create separate methods or switch/case for each and seems to belong inside the entity classes, not in some other class, no?

If an experienced C# coder can show a good design for this common problem I think I would learn a lot from it.

Happy 4th of July!

Possible Solution 1

A single XmlSerializer class with two static generic methods:

public static T Deserialize<T>(XElement xml) {}
public static XElement Serialize<T>(T entity) {}
  • Pro: Only one class (no interface needed)
  • Pro: Separates serialization responsibility from entity classes.
  • Con: Would still require separate methods or switch/case blocks for each entity type supported.
  • Con: ? Not extensible -- have to modify this class each time an entity changed or added/deleted.

Possible lessons learned?

The "can't use interface for constructors and static methods" problem might be a symptom of:

  1. Violating the SRP (Single Responsibility Principal).
  2. Violating the SoC (Separation of Concern) principal.

What about using a simple instance method for loading from XML as well? Your interface would then be something like:

public interface XmlSerializableEntity
{
   XElement Serialize(); // or ToXml() if you prefer..
   void Deserialize(XElement e); // or Load() or something like that..
}

Or you could use a generic solution:

public interface Serializable<T>
{
   T Serialize();
   void Deserialize(T e);
}

The downside is that you have to initialize the entity object before you load it, which might mean you'll have an object in an invalid state. But I do believe this is a common pattern.

It would be a good design to have the storage/retrieval separate from the entity anyway. In OO terms this can be referred to as the Single Responsibility Principle. Your entity exists for some purpose (probably related to your domain). The storage of that entity is a separate responsibility that could change independent of the domain. (eg you could retrive it from a database, a web service or the file system).

Static methods are not the only way to do this of course. You could create an interface at the save/retrive level and implement that interface for each of the entities. Then you could easily use those in a generic way without worrying a lot about the types.

Adding some example code:

interface EntityGateway<TEntity> {
    TEntity Load(String id);
    void Save(TEntity entity);
}
public class XEntityGateway implements EntityGateway<XEntity> {
    XEntity Load(String id) { ... implementation details } 
    void Save(XEntity entity) { ... implementation details } 
}

XEntityGateway gw = new XEntityGateway();
XEntity entity = gw.Load("SOMEID");
// modify entity
gw.Save(entity);

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