Mastering Factory Pattern and Application Layer Design for SOA Systems

This article explains the appropriate use cases for the Factory pattern, details the responsibilities and characteristics of the application layer in SOA systems, and provides concrete C# code examples for services, DTOs, and data assemblers to illustrate clean separation of concerns and effective data transfer.

ITFLY8 Architecture Home
ITFLY8 Architecture Home
ITFLY8 Architecture Home
Mastering Factory Pattern and Application Layer Design for SOA Systems

Factory Pattern (When to Use)

The Factory pattern is a common software design pattern, but it is not the core of Domain‑Driven Design. It should be used when object creation involves complex business rules between internal properties. For simple objects, constructors or simple factory methods suffice.

For example, when creating an Order, business rules may dictate that freight is 1% of the total amount and discounts are 75%. Encapsulating these rules in a Factory prevents the client from handling the logic directly.

Application Layer in SOA

Characteristics of the Application Layer

Coarse‑grained : The layer aggregates multiple domain objects into a single Data Transfer Object (DTO) to reduce remote calls and improve performance.

Transmissibility : DTOs carry data without business logic, isolating internal domain objects from external clients.

Encapsulation : The layer can expose services via Facade, Web Service, TCP/IP sockets, or MSMQ, keeping the model simple.

Coordination Role of the Application Layer

The application layer uses repositories to perform basic CRUD operations and delegates business logic to domain services. It should contain no business logic itself.

namespace Business.Service.ApplicationService
{
    public class PersonService
    {
        private IPersonRepository personRepository = DataAccess.CreatePersonRepository();
        public int AddPerson(Person person) { return personRepository.AddPerson(person); }
        public int UpdatePerson(Person person) { return personRepository.UpdatePerson(person); }
        public Person GetPerson(int personID) { return personRepository.GetPerson(personID); }
        public IList GetList() { return personRepository.GetList(); }
    }

    public class OrderService
    {
        private IOrderRepository orderRepository = DataAccess.CreateOrderRepository();
        public int AddOrder(Order order)
        {
            Account(order);
            return orderRepository.AddOrder(order);
        }
        private void Account(Order order)
        {
            IPersonRepository personRepository = DataAccess.CreatePersonRepository();
            Person person = personRepository.GetPerson(order.PersonID);
            AccountManager accountManager = new AccountManager(person, order);
            accountManager.Account();
        }
        public Order Payment(int orderID)
        {
            var order = orderRepository.GetOrder(orderID);
            if (order != null)
            {
                PersonRepository personRepository = new PersonRepository();
                var person = personRepository.GetPerson(order.PersonID);
                PaymentManager paymentManager = new PaymentManager();
                paymentManager.Payment(order, person);
                orderRepository.UpdateOrder(order);
                personRepository.UpdatePerson(person);
                return order;
            }
            else
                throw new Exception("Can not find order!");
        }
        // ... other CRUD methods omitted for brevity ...
    }
}

Data Transformation Process

DTOs act as carriers for remote communication. Converting between domain objects and DTOs can be complex, so a dedicated data assembler (OperationAssembler) is used.

namespace Business.Service.ApplicationService
{
    public class OperationAssembler
    {
        public static OrderDTO GetOrderDTO(Order order, Person person)
        {
            OrderDTO dto = new OrderDTO();
            if (person != null)
            {
                dto.EMail = person.EMail.GetString();
                dto.Address = person.Address.GetString();
                dto.Name = person.Name.GetString();
                dto.PersonID = person.ID;
                dto.Point = person.Point.GetInt();
                dto.Telephone = person.Telephone.GetString();
            }
            if (order != null)
            {
                dto.PersonID = order.PersonID;
                dto.Count = order.Count.GetInt();
                dto.Delivery = order.Delivery.GetDateTime();
                dto.Favorable = order.Favorable.GetDouble();
                dto.Freightage = order.Freightage.GetDouble();
                dto.OrderID = order.ID;
                dto.OrderNumber = order.OrderNumber.GetString();
                dto.Price = order.Price.GetDouble();
                dto.TotalPrice = order.TotalPrice.GetDouble();
                var items = order.OrderItem.ToList();
                if (items.Count != 0)
                {
                    var itemDtos = new List<OrderItemDTO>();
                    foreach (var item in items)
                        itemDtos.Add(GetOrderItemDTO(item));
                    dto.OrderItemList = itemDtos;
                }
            }
            return dto;
        }
        public static OrderItemDTO GetOrderItemDTO(OrderItem item)
        {
            OrderItemDTO dto = new OrderItemDTO();
            dto.Count = item.Count.GetInt();
            dto.Goods = item.Goods.GetString();
            dto.OrderID = item.OrderID;
            dto.OrderItemID = item.ID;
            dto.Price = item.Price.GetDouble();
            return dto;
        }
        public static void SetOrder(OrderDTO dto, out Person person, out Order order)
        {
            person = new Person();
            person.EntityKey = new System.Data.EntityKey("BusinessContext.Person","ID",dto.PersonID);
            person.Address = dto.Address;
            person.EMail = dto.EMail;
            person.ID = dto.PersonID;
            person.Name = dto.Name;
            person.Point = dto.Point;
            person.Telephone = dto.Telephone;

            order = new Order();
            order.EntityKey = new System.Data.EntityKey("BusinessContext.Order","ID",dto.OrderID);
            order.Count = dto.Count;
            if (dto.Delivery.Year != 0001 && dto.Delivery.Year != 9999)
                order.Delivery = dto.Delivery;
            order.Favorable = dto.Favorable;
            order.Freightage = dto.Freightage;
            order.ID = dto.OrderID;
            order.OrderNumber = dto.OrderNumber;
            order.PersonID = dto.PersonID;
            order.Price = dto.Price;
            order.TotalPrice = dto.TotalPrice;
            if (dto.OrderItemList != null && dto.OrderItemList.Count != 0)
                foreach (var itemDto in dto.OrderItemList)
                    order.OrderItem.Add(GetOrderItem(itemDto));
        }
        public static OrderItem GetOrderItem(OrderItemDTO dto)
        {
            OrderItem item = new OrderItem();
            item.EntityKey = new System.Data.EntityKey("BusinessContext.OrderItem","ID",dto.OrderItemID);
            item.Count = dto.Count;
            item.Goods = dto.Goods;
            item.ID = dto.OrderItemID;
            item.OrderID = dto.OrderID;
            item.Price = dto.Price;
            return item;
        }
    }
}

// DTO definitions
namespace Business.TransferObject
{
    [DataContract]
    public class OrderItemDTO
    {
        [DataMember] public int OrderItemID { get; set; }
        // other members omitted for brevity
    }
    [DataContract]
    public class OrderDTO
    {
        [DataMember] public int PersonID { get; set; }
        // other members omitted for brevity
    }
}

Publishing Application Layer Services

Application services are exposed via remote methods (e.g., WCF). A Facade aggregates the few remote service classes.

namespace Business.Service.ApplicationService
{
    [ServiceContract]
    public interface IOperationService
    {
        [OperationContract] int AddOrder(ref OrderDTO orderDTO);
        [OperationContract] int DeleteOrder(OrderDTO orderDTO);
        [OperationContract] int UpdateOrder(ref OrderDTO orderDTO);
        [OperationContract] IList GetOrderByPerson(int personID);
        [OperationContract] OrderDTO GetOrder(int orderID);
        // ... other operations omitted ...
    }

    public class OperationService : IOperationService
    {
        [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
        public int AddOrder(ref OrderDTO orderDTO)
        {
            OrderService svc = new OrderService();
            Order order = GetOrder(orderDTO);
            int n = svc.AddOrder(order);
            orderDTO = OperationAssembler.GetOrderDTO(order, null);
            return n;
        }
        // ... other method implementations omitted for brevity ...
    }
}

Overall System Architecture

DDD‑Based Architecture

The repository layer maps persistence data to domain objects, domain services contain business logic, the application layer coordinates repositories and domain services, and a data assembler converts domain objects to DTOs for remote transmission.

Service‑Oriented Architecture

SOA separates the presentation layer from the application service layer via remote communication, allowing independent development of functional modules that can be combined through services, a precursor to cloud computing.

Conclusion

The article shares practical experiences in building a DDD‑driven SOA system, emphasizing clean separation of concerns, proper use of the Factory pattern, and the importance of DTOs and remote services for scalable architecture.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DDDFactory PatternApplication LayerSOAC#
ITFLY8 Architecture Home
Written by

ITFLY8 Architecture Home

ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.