lserafin / DDD

Domain-Driven Design is a software development approach in which it utilizes concepts and good practices related to object-oriented programming.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Domain-Driven Design

Domain-Driven Design is a software development approach in which it utilizes concepts and good practices related to object-oriented programming.

Books

Domain-Driven Design: Tackling Complexity in the Heart of Software - Eric Evans Implementing Domain-Driven Design - Vaughn Vernon

Tests

[TestClass]
public class Tests
{
    [TestMethod]
    public void Email()
    {
        var text = new Email("domain.com");
        var empty = new Email(string.Empty);
        var email = new Email("email@domain.com");

        Assert.IsTrue(text.Invalid);
        Assert.IsTrue(empty.Invalid);
        Assert.IsTrue(email.Valid);
    }

    [TestMethod]
    public void Order()
    {
        var customer = CustomerFactory.Create("Luke", "Skywalker", "luke.skywalker@starwars.com");

        var product = ProductFactory.Create("Millennium Falcon", 500_000_000);

        var item = OrderItemFactory.Create(product, 1);

        var order = OrderFactory.Create(customer);

        order.AddItem(item);

        var discount = new DiscountService().Calculate(order.Total, DiscountType.Large);

        order.ApplyDiscount(discount);

        Assert.AreEqual(250_000_000, order.Total.Value);
    }
}

Customer

public sealed class Customer : Entity
{
    public Customer(FullName fullName, Email email)
    {
        FullName = fullName;
        Email = email;
    }

    public Email Email { get; private set; }

    public FullName FullName { get; private set; }

    public void ChangeEmail(Email email)
    {
        Email = email;
    }

    public void ChangeFullName(FullName fullName)
    {
        FullName = fullName;
    }
}
public static class CustomerFactory
{
    public static Customer Create(string firstName, string lastName, string email)
    {
        return new Customer(new FullName(firstName, lastName), new Email(email));
    }
}

Product

public sealed class Product : Entity
{
    public Product(string description, Amount price)
    {
        Description = description;
        Price = price;
    }

    public string Description { get; private set; }

    public Amount Price { get; private set; }

    public void ChangeDescription(string description)
    {
        Description = description;
    }

    public void ChangePrice(Amount price)
    {
        Price = price;
    }
}
public static class ProductFactory
{
    public static Product Create(string description, decimal price)
    {
        return new Product(description, new Amount(price));
    }
}

Order

public sealed class Order : Entity
{
    public Order(Customer customer)
    {
        Customer = customer;
        Discount = new Amount(0);
        Items = new List<OrderItem>();
    }

    public Customer Customer { get; private set; }

    public Amount Discount { get; private set; }

    public IReadOnlyList<OrderItem> Items { get; private set; }

    public Amount Total => new Amount(Items.Sum(item => item.SubTotal.Value) - Discount.Value);

    public void AddItem(OrderItem item)
    {
        Items = new List<OrderItem>(Items) { item };
    }

    public void ApplyDiscount(Amount discount)
    {
        Discount = discount;
    }
}
public static class OrderFactory
{
    public static Order Create(Customer customer)
    {
        return new Order(customer);
    }
}

Order Item

public sealed class OrderItem : Entity
{
    public OrderItem(Product product, Quantity quantity)
    {
        Product = product;
        Quantity = quantity;
    }

    public Product Product { get; private set; }

    public Quantity Quantity { get; private set; }

    public Amount SubTotal => new Amount(Product.Price.Value * Quantity.Value);
}
public static class OrderItemFactory
{
    public static OrderItem Create(Product product, decimal quantity)
    {
        return new OrderItem(product, new Quantity(quantity));
    }
}

Discount

public enum DiscountType
{
    Small = 1,
    Medium = 2,
    Large = 3
}
public sealed class DiscountService
{
    public Amount Calculate(Amount amount, DiscountType type)
    {
        var discount = Factory.Get<IDiscount>(x => x.IsApplicable(type));

        if (discount == null) { return amount; }

        return discount.Calculate(amount);
    }
}
public interface IDiscount
{
    Amount Calculate(Amount amount);

    bool IsApplicable(DiscountType type);
}
public sealed class SmallDiscount : IDiscount
{
    public Amount Calculate(Amount amount)
    {
        return new Amount(amount.Value * 0.1M);
    }

    public bool IsApplicable(DiscountType type) => type == DiscountType.Small;
}
public sealed class MediumDiscount : IDiscount
{
    public Amount Calculate(Amount amount)
    {
        return new Amount(amount.Value * 0.25M);
    }

    public bool IsApplicable(DiscountType type) => type == DiscountType.Medium;
}
public sealed class LargeDiscount : IDiscount
{
    public Amount Calculate(Amount amount)
    {
        return new Amount(amount.Value * 0.5M);
    }

    public bool IsApplicable(DiscountType type) => type == DiscountType.Large;
}

Value Objects

public sealed class Amount : ValueObject<decimal>
{
    public Amount(decimal value) : base(value) { }

    public override string ToString() => Value.ToString();
}
public sealed class Email : ValueObject<string>
{
    public Email(string value) : base(value) { }

    public bool Invalid => !Valid;

    public bool Valid
    {
        get
        {
            if (string.IsNullOrWhiteSpace(Value)) { return false; }

            const string regex = @"^([a-z0-9_\.\-]{3,})@([\da-z\.\-]{3,})\.([a-z\.]{2,6})$";

            return new Regex(regex).IsMatch(Value);
        }
    }

    public override string ToString() => Value.ToString();
}
public sealed class FullName : ValueObject
{
    public FullName(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

    public override string ToString() => $"{ FirstName } { LastName }";

    protected override IEnumerable<object> Equals()
    {
        yield return FirstName;
        yield return LastName;
    }
}
public sealed class Quantity : ValueObject<decimal>
{
    public Quantity(decimal value) : base(value) { }

    public override string ToString() => Value.ToString();
}

About

Domain-Driven Design is a software development approach in which it utilizes concepts and good practices related to object-oriented programming.

License:MIT License


Languages

Language:C# 100.0%