mirror of https://github.com/abpframework/abp.git
5 changed files with 143 additions and 4 deletions
@ -1,3 +1,75 @@ |
|||
## Value Objects |
|||
# Value Objects |
|||
|
|||
TODO |
|||
> An object that represents a descriptive aspect of the domain with no conceptual identity is called a VALUE OBJECT. |
|||
> |
|||
> (Eric Evans) |
|||
|
|||
Two [Entities](Entities.md) with the same properties but with different `Id`s are considered as different entities. However, Value Objects have no `Id`s and they are considered as equals if they have the same property values. |
|||
|
|||
## The ValueObject Class |
|||
|
|||
`ValueObject` is an abstract class that can be inherited to create a Value Object class. |
|||
|
|||
**Example: An Address class** |
|||
|
|||
````csharp |
|||
public class Address : ValueObject |
|||
{ |
|||
public Guid CityId { get; private set; } |
|||
|
|||
public string Street { get; private set; } |
|||
|
|||
public int Number { get; private set; } |
|||
|
|||
private Address() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public Address( |
|||
Guid cityId, |
|||
string street, |
|||
int number) |
|||
{ |
|||
CityId = cityId; |
|||
Street = street; |
|||
Number = number; |
|||
} |
|||
|
|||
protected override IEnumerable<object> GetAtomicValues() |
|||
{ |
|||
yield return Street; |
|||
yield return CityId; |
|||
yield return Number; |
|||
} |
|||
} |
|||
```` |
|||
|
|||
* A Value Object class must implement the `GetAtomicValues()` method to return the primitive values. |
|||
|
|||
### ValueEquals |
|||
|
|||
`ValueObject.ValueEquals(...)` method is used to check if two Value Objects are equals. |
|||
|
|||
**Example: Check if two addresses are equals** |
|||
|
|||
````csharp |
|||
Address address1 = ... |
|||
Address address2 = ... |
|||
|
|||
if (address1.ValueEquals(address2)) //Check equality |
|||
{ |
|||
... |
|||
} |
|||
```` |
|||
|
|||
## Best Practices |
|||
|
|||
Here are some best practices when using Value Objects: |
|||
|
|||
- Design a value object as **immutable** (like the Address above) if there is not a good reason for designing it as mutable. |
|||
- The properties that make up a Value Object should form a conceptual whole. For example, CityId, Street and Number shouldn't be separate properties of a Person entity. This also makes the Person entity simpler. |
|||
|
|||
## See Also |
|||
|
|||
* [Entities](Entities.md) |
|||
@ -0,0 +1,36 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.Domain.Values |
|||
{ |
|||
public class Address : ValueObject |
|||
{ |
|||
public Guid CityId { get; } |
|||
|
|||
public string Street { get; } |
|||
|
|||
public int Number { get; } |
|||
|
|||
private Address() |
|||
{ |
|||
} |
|||
|
|||
public Address( |
|||
Guid cityId, |
|||
string street, |
|||
int number) |
|||
{ |
|||
CityId = cityId; |
|||
Street = street; |
|||
Number = number; |
|||
} |
|||
|
|||
//Requires to implement this method to return properties.
|
|||
protected override IEnumerable<object> GetAtomicValues() |
|||
{ |
|||
yield return Street; |
|||
yield return CityId; |
|||
yield return Number; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using System; |
|||
using Shouldly; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.Domain.Values |
|||
{ |
|||
public class ValueObject_Tests |
|||
{ |
|||
[Fact] |
|||
public void ValueObjects_With_Same_Properties_Should_Be_Equals() |
|||
{ |
|||
var cityId = Guid.NewGuid(); |
|||
var address1 = new Address(cityId, "Baris Manco", 42); |
|||
var address2 = new Address(cityId, "Baris Manco", 42); |
|||
|
|||
address1.ValueEquals(address2).ShouldBeTrue(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ValueObjects_With_Different_Properties_Should_Not_Be_Equals() |
|||
{ |
|||
var cityId = Guid.NewGuid(); |
|||
|
|||
var address1 = new Address(cityId, "Baris Manco", 42); |
|||
var address2 = new Address(cityId, "Baris Manco", 42); |
|||
|
|||
address1.ValueEquals(address2).ShouldBeFalse(); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue