-1

Preface

In an application that is separated by layers or distributed by services it is common to have classes that are very closely related data-wise, but which we wish to have loosely coupled. My usual solution (in c#) is to have them implement a common interface. (There are other patterns, but this is what I default to)

I might (for example) have a backend data entity Foo

public class Foo:IFoo
{
    public int DatabaseKey {get; set;}
    public string NaturalKey {get; set;}
    public string SomeProperty {get; set;}
}

a data contract class FooDto

[DataContract]
public class FooDto:IFoo
{
    [DataMember]
    public string NaturalKey {get; set;}
    [DataMember]
    public string SomeProperty {get; set;}
}

and an MVC model class FooModel

public class FooModel:IFoo
{
    public string NaturalKey {get; set;}
    public string SomeProperty {get; set;}
    public string CssClass {get; set;}
}

all implementing a common interface IFoo

public interface IFoo
{
    string NaturalKey {get;}
    string SomeProperty {get;}
}

My Question

When mapping those incarnations of Foo onto each other I might use an object mapper (ie automapper), but for smaller projects or when policy prevents third party software I add a constructor which takes the interface as a parameter, ie

public Foo(IFoo template):base()
{
    NaturalKey = template.NaturalKey;
    SomeProperty = template.SomeProperty;
    //additional code
}

etc

How can I avoid unnecessarily repeating the assignments from template to properties across the different classes? Assume that the general pattern is given as is the decision not to use an object mapper. Note that the assignments might differ in some cases (inferring explicit defaults for null values etc)

  • 1
    use reflection and write your own automapper – Ewan Nov 1 '17 at 8:32
  • 1
    "...when policy prevents third party software...". So you write your own framework, compiler, IDE, etc? No company genuinely has a "no third party software" policy. Microsoft might have at one stage, but even they use other people's software these days. So challenge the policy. – David Arno Nov 1 '17 at 8:59
  • @Ewan What's the net gain in that? I'll end up with spending more hours on a worse solution . If an object mapper is a better solution than custom constructors, I'll use it. – Guran Nov 1 '17 at 10:03
  • @DavidArno Yes, I'd challenge a policy if warranted. But I wont spend days arguing about a policy change just to save hours of coding. – Guran Nov 1 '17 at 10:05
  • 1
    @Guran you said policy prevents the use of third party libraries. If you wrote your own you could reuse it as required and a simple one would be quick to write. Theres no other way to 'reduce code', maybe you code use templates to automate the long hand approach instead – Ewan Nov 1 '17 at 10:43
-2

None of the objects has to contain properties where its data reside. Objects are not data containers, they are smart units of behavior. You could embrace what Alan Kay, a man behind Smalltalk, thought about objects. He wanted them to get rid of data. So if you need to persist them, ok, it might look like that:

class User
{
    private $id;
    private $dataSource;

    public function __construct(UUID $id, DataSource $dataSource)
    {
        $this->id = $id;
        $this->dataSource = $dataSource;
    }

    public function register(FullName $fullName, Passport $passport, Email $email)
    {
        $this->dataSource
            ->save(
                $this->id,
                $fullName,
                $passport,
                $email
            )
        ;
    }
}

This approaches solves the root problem: treating object like data bags. It reflects a procedural mindset that encompasses a good part of software developers. You could try different hacks and workarounds, like using reflection or passing a DTO to model entity, but it doesn't solve the root cause of your problem. Basically, any object should possess all resources it needs to implement its responsibilities. Here are some more examples and guidelines.

Anticipating your question about how to avoid copy-pasting data to View or ModelView classes, the answer is the same. In OOP, any object is responsible for displaying itself. So your object could return an xml object that could be represented in browser with XSLT:

class User
{
    private $id;
    private $dataSource;

    public function __construct(UUID $id, DataSource $dataSource)
    {
        $this->id = $id;
        $this->dataSource = $dataSource;
    }

    public function display()
    {
        $data = $this->dataSource->byId($this->id);

        return
            (new Xml())
                ->add('name', $data['name'])
                ->add('passport_number', $data['passport_number'])
                ->add('email', $data['email'])
            ;
    }
}

Here is more about this technique.

Once again, unless you stop treating your program as a flow of passive data that is operated upon some procedures, you'll never get rid of constant getting-and-setting since it is the nature of procedural programming.

  • 4
    This is a great answer to a question I didn't ask. Yes, I could use a different OOP pattern alltogether, or go FP, but I'm asking for a way to refactor the existing solution. – Guran Nov 1 '17 at 9:04
  • 1
    -1 because this is not an appropriate answer to the question. – Emerson Cardoso Nov 1 '17 at 10:47
  • Guran, the intrinsic nature of the approach you use implies copy-paste. Any answer would inevitably represent some shade of procedural ugliness, as I noted in my answer. The answer to your question as you posed it doesn't exist. That's why I tried to target the core problem. – Zapadlo Nov 1 '17 at 11:33
  • @Zapadlo You might very well be right. If I knew a good answer I wouldn't have asked the question :) Still, there are more clever programmers than me out there. – Guran Nov 1 '17 at 12:33
-2

These kinds of classes are essentially data structures used to move data across the boundaries of the application, and so are not objects in the OOP sense. The classes generally have no logic, or have very little logic, and mostly act as property bags.

And, unless I'm mistaken, one of the key things they need to support in the scenario you describe is copying property values from one type to another; one way to support that is to have your IFoo interface declare read/write properties.

public interface IFoo
{
    string NaturalKey {get; set;}
    string SomeProperty {get; set;}
}

Then you could simply define an extension method that takes two IFoo instances, and copies the properties:

public static void CopyFrom(this IFoo destination, IFoo source) 
{
    destination.NaturalKey = source.NaturalKey;
    destination.SomeProperty = source.SomeProperty;
}

You can then use it like this:

foo1.CopyFrom(foo2);

You may feel that this is not entirely OO, but applications are not object oriented at the boundaries, and that's where these classes appear.

P.S. I understand that there could be something that prevents you to use this approach, and that there could be a good reason behind your decision to declare the interface with with get-only properties - but maybe you can adapt the idea somehow to suit your case.

  • Yes, extension methods is one pragmatic way to do this. (Actually that would be my answer if someone else posted this question) You identified the drawback yourself. (forcing setters in the interface) Sometimes an issue sometimes not. YMMV... Good answer. – Guran Nov 1 '17 at 11:24
  • Something you could try is to define two interfaces - one that has get-only properties, and another one that defines both getters and setters - then implement one or both as needed (I think implementing both at the same time should compile/work). Then you could change the signature of the extension method to: void CopyFrom(this IFoo destination, IFooGetOnly source). You could also try doing something with reflection, but that again puts certain constraints on your types (but then again, so does automapper). – Filip Milovanović Nov 1 '17 at 11:59
-3

You could write a base class that performs a default copy of all properties, assigning default values (which need to be implemented by subclasses) if property values are not valid.

Example:

public interface IFoo
{
    string NaturalKey {get;}
    string SomeProperty {get;}
}

public abstract class BaseFoo : IFoo
{
    public string NaturalKey {get;}
    public string SomeProperty {get;}

    public abstract string DefaultNaturalKey {get;}
    public abstract string DefaultSomeProperty {get;}

    protected void CopyFrom(IFoo sourceFoo) 
    {
        if (string.IsNullOrEmpty(sourceFoo.NaturalKey)) 
        {
            NaturalKey = DefaultNaturalKey;
        } 
        else
        {
            NaturalKey = sourceFoo.NaturalKey;
        }

        if (string.IsNullOrEmpty(sourceFoo.SomeProperty)) 
        {
            SomeProperty = DefaultSomeProperty;
        } 
        else
        {
            SomeProperty = sourceFoo.SomeProperty;
        }

        //...and so on...
    }
}

public class Foo : BaseFoo {

    public override string DefaultNaturalKey { get { return "MyKey"; } }
    public override string DefaultSomeProperty { get { return "MyProperty"; } }

    public Foo(IFoo template) : base()
    {
        CopyFrom(template);

        //additional assignments, if necessary
    }
}
  • I could, but then I'd introduce a hard(er) coupling between the different Foos. If an abstract base class is justified, why use an interface to begin with? – Guran Nov 1 '17 at 10:08
  • The interface here still exists (anywhere in code referencing it wouldn't need to change). You could either inherit from this BaseFoo, or use composition in order to reuse the code and avoid repetition. Either way, you need some base assignment code somewhere, and in your subclasses you call the base code, and perform some specific assignments (which you said it was necessary in some cases). Other than that, you have the reflection option mentioned in the comments. – Emerson Cardoso Nov 1 '17 at 10:27
  • The problem of coupling here is a bit subtle. You use these classes to decouple parts of your application that are at different sides of layer boundaries. To decouple two components, you make them both depend on an abstraction (Dependency inversion principle), and these classes, in a way, provide that abstraction for the layers, in the form of data. That said, you've already introduced coupling between them by having them implement the same interface; making it an abstract class doesn't really make that much of a difference - unless you need to inherit from something else. – Filip Milovanović Nov 1 '17 at 10:40
  • 1
    -1 because this is a procedural hell. – Zapadlo Nov 1 '17 at 10:56
  • @FilipMilovanović Correct. This pattern could easily be abused to make the coupling harder than intended. As used the interface is merely a data contract of sorts. And you are correct again, the reason I'm avoiding a base class is that I want to keep the option to let for example Foo and Bar inherit some common behaviour. – Guran Nov 1 '17 at 11:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.