Posts
58
Comments
103
Trackbacks
10
Wednesday, October 10, 2007
Operator Overloads and Value Objects

In many cases, we tend to overlook important abstractions in our object models.  Emails and Phone Numbers are two common ones.  A lot of times these are immutable value objects, to borrow from DDD.  A lot of these guys are perfect for operator overloading.  Here's a simple example:

 

    public class Email : IEquatable<Email>
    {
        public Email(string address)
        {
            if (string.IsNullOrEmpty(address) || ! Validate(address))
            {
                throw new InvalidEmailException(address);                
            }
            _address = address;
        }

        private bool Validate(string address)
        {
            //insert simple regex here
            return true;
        }

        private readonly string _address;

        public string Address
        {
            get { return _address; }
        }

        public static implicit operator Email(string address)
        {
            return new Email(address);
        }

        public static implicit operator string(Email email)
        {
            return email.Address;
        }

        public bool Equals(Email email)
        {
            if (email == null) return false;
            return Equals(_address, email._address);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj)) return true;
            return Equals(obj as Email);
        }

        public override int GetHashCode()
        {
            return _address.GetHashCode();
        }
    }


There's a bit of noise there, but here's what it gives us:

            Email me = "myfirstname@evanhoff.com";
            string address = me;


How about a little design by contract goodness:

 

    public class EmailSender
    {
        public void Send(Email to, Email from, string subject, string body)
        {
            //implementation
        }
    }

With usage:

            EmailSender sender = new EmailSender();
            sender.Send("myfirstname@evanhoff.com", "johndoe@hotmail.com", "test subject", "test body");


You'll notice that the compiler will automagically use the implicit string conversion.  In addition, we have DbC enforced as part of the conversion process.  You'll also notice I overrode Equals and GetHashCode for value-based comparison semantics (ok, ok, so ReSharper overrode them for me..lol).

This works great for a lot of other "missing abstractions" also.

 

    public class Phone : IEquatable<Phone>
    {
        private readonly string _number;

        public Phone(string number)
        {
            if (string.IsNullOrEmpty(number) || ! Validate(number))
            {
                throw new InvalidPhoneException(number);
            }
            _number = number;
        }

        private bool Validate(string number)
        {
            //insert validation here
            return true;
        }

        public string Number
        {
            get { return _number; }
        }

        public static implicit operator Phone(string number)
        {
            return new Phone(number);
        }

        public static implicit operator string(Phone phone)
        {
            return phone.Number;
        }

        public bool Equals(Phone phone)
        {
            if (phone == null) return false;
            return Equals(_number, phone._number);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj)) return true;
            return Equals(obj as Phone);
        }

        public override int GetHashCode()
        {
            return _number.GetHashCode();
        }
    }

    public class InvalidPhoneException : Exception
    {
        private readonly string _number;

        public InvalidPhoneException(string number)
        {
            _number = number;
        }

        public string Number
        {
            get { return _number; }
        }

        public override string Message
        {
            get { return string.Format("Invalid Phone Number: {0}", _number); }
        }
    }
Note: All of the above is "blog code".  It doesn't have unit tests, so I'm not going to say it's bug free.
posted @ Wednesday, October 10, 2007 11:40 PM | Feedback (4)
Simple Object-Orientation and Component-Orientation Side by Side

Object-Orientation:

 


Component-Orientation:


 

Looking at the example above, I notice there's a fairly large discrepancy in lines of code.  That was mostly a consequence of the trivial example I am using.  Don't read into that.

There's more coming on this stuff, but this is enough for today.  Next, we can look at the two forms of inheritance.

posted @ Wednesday, October 10, 2007 11:12 PM | Feedback (1)
Component Orientation

Yes, people, fasten your seatbelts.  Time for a quick introduction to an often misunderstood topic.  The term "component" is about as overloaded as the terms "service" and "object".  Please read this with your "curiosity" hat on.  I'm only attempting to inform here.

Pick a random developer off the street, and they will probably even give the same definition for each.  They are all about creating abstractions on a problem domain.  They all claim to promote reuse.  They all promote encapsulation.  And, they are all generally misunderstood and misapplied in the .NET community.

So what's the difference?  The difference between an object and a service is probably the easiest to see, but what about that component?  Let's focus on the object and the component for now.

Principles of Object-Orientation:

  • Single Responsibility Principle
  • Open/Closed Principle
  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle
  • Single Choice Principle
  • Stable Abstractions Principle

Packaging Principles:

  • Acyclic Dependencies Principle
  • Release Reuse Equivalency Principle
  • Common Closure Principle
  • Common Reuse Principle
  • Acyclic Dependencies Principle
  • Stable Dependencies Principle
  • Stable Abstractions Principle

If these look foreign to you, I'd recommend you skip the rest of this article and grab a good book on OOP.  It'll change your professional life forever, I promise.  I often recommend Bob Martin's book.  He also has some great PDF articles available on the web (under Design Principles).

I'm largely going to skip over the OO stuff and assume you have a good handle on that programming paradigm.

I'll skip the fluff and go straight for the meat on components.

Defining a software component:

A software component is a unit of composition with contractually specified interfaces and explicit context dependencies only.  A software component can be deployed independently and is subject to composition by third parties.

--From the 1996 European Conference on OO Programming

Characteristics of a software component [Szy]:

  • is a unit of independent deployment
  • is a unit of third party composition
  • has no externally visible state

Characteristics of an object [Szy]:

  • is a unit of instantiation, each instantiation has a unique identity
  • may have state, and its state may be externally visible
  • encapsulates state and behavior

Principles of Component-Orientation [Low]:

  • Separation of Interface and Implementation
  • Binary Compatibility
  • Language Independence
  • Location Transparency
  • Concurrency Management
  • Version Control
  • Component-based Security

Tomorrow we will take a deeper look at what this means in terms of c# code and our development environment.

[Szy] : Component Software by Clemens Szyperski
[Low] : Programming .NET Components by Juval Lowy

posted @ Wednesday, October 10, 2007 12:54 AM | Feedback (3)