学习用于CRM应用的C语言的类

225 阅读5分钟

到目前为止,我们一直在研究如何在C#中创建一个类,然后向其添加属性和方法的具体细节。现在我们想给应用程序添加额外的类。这是一个客户关系管理类型的应用程序,所以我们需要像订单类、产品类、OrderItem类,以及其他一些类。在本教程中,我们将开始构建这些类,以便与我们现有的Customer类一起工作,同时注意耦合、凝聚、关注点分离和设计模式等要素。

首先,让我们定义一下耦合、凝聚、关注点分离和设计模式。

  • 耦合是指类之间相互依赖的程度。
  • 凝聚力是指类的成员与类的目的相关的程度。
  • 关注点分离(Separation of Concerns)告诉我们要将一个应用程序分解成重叠度最小的部分。每个部分都负责一个单独的关注点。
  • 设计模式是定义适当的类和它们的相关关系的通用做法。

产品类

我们的产品类的代码如下所示,首先我们可以看到,它有一个构造函数,接受一个整数id,代表 productId.它还有几个属性,我们可以用它们来表示一个产品。一个产品会有哪些东西呢?它有一些东西,比如a CurrentPrice, a ProductId, a ProductDescription,和a ProductName.此外,有一个 Validate()的方法,它验证了 ProductName的完整性,以及 CurrentPrice.我们也有一个 Retrieve()Save()方法。这个类的文件名是Product.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CRMBIZ
{
    public class Product
    {
        public Product()
        {

        }

        public Product(int productId)
        {
            this.ProductId = productId;
        }

        public Decimal? CurrentPrice { get; set; }
        public int ProductId { get; private set; }
        public string ProductDescription { get; set; }
        public string ProductName { get; set; }

        public Product Retrieve(int productId)
        {
            return new Product();
        }

        public bool Save()
        {
            return true;
        }

        public bool Validate()
        {
            var isValid = true;

            if (string.IsNullOrWhiteSpace(ProductName)) isValid = false;
            if (CurrentPrice == null) isValid = false;

            return isValid;
        }
    }
}


订单类

订单类也使用了一个默认的构造函数,以及一个辅助构造函数,该构造函数接受一个整数代表 orderId.订单类有两个属性 OrderDateOrderId.我们也可以看到这些相同的方法 Retrieve(), Save()Validate().订单类的文件名是Order.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CRMBIZ
{
    public class Order
    {
        public Order()
        {

        }

        public Order(int orderId)
        {
            this.OrderId = orderId;
        }

        public DateTimeOffset? OrderDate { get; set; }
        public int OrderId { get; private set; }

        public Order Retrieve(int orderId)
        {
            return new Order();
        }

        public bool Save()
        {
            return true;
        }

        public bool Validate()
        {
            var isValid = true;

            if (OrderDate == null) isValid = false;

            return isValid;
        }
    }
}

OrderItem类

我们的CRM应用大纲中的最后一个类将是OrderItem类,它被列在下面。一切看起来都很好,但我们确实看到,所有这些类都有许多方法。我们可能要对这些方法进行一些重构。按照惯例,OrderItem类的文件名是OrderItem.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CRMBIZ
{
    public class OrderItem
    {
        public OrderItem()
        {

        }

        public OrderItem(int orderItemId)
        {
            this.OrderItemId = orderItemId;
        }
        public int OrderItemId { get; private set; }
        public int OrderQuantity { get; set; }
        public int ProductId { get; set; }
        public decimal? PurchasePrice { get; set; }

        public OrderItem Retrieve(int orderItemId)
        {
            return new OrderItem();
        }

        public bool Save()
        {
            return true;
        }

        public bool Validate()
        {
            var isValid = true;

            if (OrderQuantity <= 0) isValid = false;
            if (ProductId <= 0) isValid = false;
            if (PurchasePrice == null) isValid = false;

            return isValid;
        }
    }
}

重构类的责任

到目前为止,我们有一个客户产品订单OrderItem类。这是一个很好的开始,可以代表一个基本的CRM应用。然而,有几个问题。所有这些类都有一个 Retrieve()Save()方法,可以提取到一个存储库类中。此外,我们应该从客户类中移除一些责任,并将其放在地址类中。让我们现在开始解决这些问题。


地址类

下面是地址类的代码,可以在Address.cs中找到。它被用来表示一个地址,其属性为 AddressId, AddressType, StreetLine1, StreetLine2, City, State, PostalCode、 、 和 Country.刚好可以完成它的工作。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CRMBIZ
{
    public class Address
    {
        public Address()
        {

        }

        public Address(int addressId)
        {
            this.AddressId = addressId;
        }

        public int AddressId { get; private set; }
        public int AddressType { get; set; }
        public string StreetLine1 { get; set; }
        public string StreetLine2 { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string PostalCode { get; set; }
        public string Country { get; set; }

    }
}

为数据持久性创建存储库类

上面的原始类可以从删除 Retrieve()Save()方法可以从中受益。存储库类可以处理与数据库的交互。这个逻辑不需要像上面那样在每一个类中重新创建。最好是将这些逻辑提取出来,放在自己的资源库中。使用资源库模式是面向对象编程中一个非常流行的惯例,在C#、Java、PHP等中都有。


CustomerRepository类

在这个类中,我们需要做的是将客户类中的Retrieve()Save()方法剪切并粘贴到这个存储库类中。这样一来,与数据库交互的工作就被放在自己的类中,以便更好地分离问题。它的文件名是CustomerRepository.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CRMBIZ
{
    public class CustomerRepository
    {
        public Customer Retrieve(int customerId)
        {
            Customer customer = new Customer(customerId);

            if (customerId == 1)
            {
                customer.EmailAddress = "swilliams@greenenergy.com";
                customer.FirstName = "Susan";
                customer.LastName = "Williams";
            }
            return customer;
        }

        public List<Customer> Retrieve()
        {
            return new List<Customer>();
        }

        public bool Save()
        {
            return true;
        }

    }
}

OrderRepository类

我们还可以创建一个OrderRepository类来处理与数据存储的交互,把这个功能从基类Order中移出来。因此,再次将Retrieve()和Save()的代码从Order类中移出,现在将它们放在OrderRepository类中。请注意,到目前为止,在所有这些存储库类的例子中,我们只是用硬编码来表示一个订单或一个产品等。与数据库交互的实际代码可以在以后添加。现在我们这样设置,我们甚至可以创建一些自动测试来确保代码的工作。下面是OrderRepository.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CRMBIZ
{
    public class OrderRepository
    {
        public Order Retrieve(int orderId)
        {
            Order order = new Order(orderId);

            if (orderId == 10)
            {
                order.OrderDate = new DateTimeOffset(2019, 4, 14, 10, 00, 00, new TimeSpan(7, 0, 0));
            }
            return order;
        }

        public bool Save()
        {
            return true;
        }
    }
}

产品资源库类

这个类被设置为public,我们再次将Retrieve()和Save()方法从Product类中移出,放到ProductRepository类中。这些方法再次使用一些简单的硬编码数据来模拟与数据库的工作。这里是ProductRepository.cs文件。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CRMBIZ
{
    public class ProductRepository
    {
        public Product Retrieve(int productId)
        {
            Product product = new Product(productId);

            if (productId == 2)
            {
                product.ProductName = "Lenovo Laptop";
                product.ProductDescription = "Carbon X1";
                product.CurrentPrice = 1599.99M;
            }
            return product;
        }

        public bool Save()
        {
            return true;
        }

    }
}

AddressRepository类

我们可以创建的最后一个资源库类是AddressRepository.cs类。这个类比较复杂,因为它可以检索一个客户的单个地址或地址列表。RetrieveByCustomerId()方法返回一个IEnumerable。IEnumerable是返回数据序列的推荐方式,因为其结果为方法的调用者提供了更多的灵活性。这个方法需要一个参数,客户ID是一个整数值。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CRMBIZ
{
    public class AddressRepository
    {
        public Address Retrieve(int addressId)
        {
            Address address = new Address(addressId);

            if (addressId == 1)
            {
                address.AddressType = 1;
                address.StreetLine1 = "Microsoft Way";
                address.StreetLine2 = "C# Blvd";
                address.City = "Seattle";
                address.State = "Washington";
                address.Country = "United States";
                address.PostalCode = "98052";

            }
            return address;
        }

        public IEnumerable<Address> RetrieveByCustomerId(int customerId)
        {
            var addressList = new List<Address>();
            Address address = new Address(1)
            {
                AddressType = 1,
                StreetLine1 = "Microsoft Way",
                StreetLine2 = "C# Blvd",
                City = "Seattle",
                State = "Washington",
                Country = "United States",
                PostalCode = "98052"
            };
            addressList.Add(address);

            address = new Address(2)
            {
                AddressType = 2,
                StreetLine1 = "Happy Island",
                City = "Saltwater Shores",
                State = "Washington",
                Country = "United States",
                PostalCode = "98569"
            };
            addressList.Add(address);

            return addressList;
        }

        public bool Save(Address address)
        {
            return true;
        }
    }
}

测试 CustomerRepository 类

我们可以使用类似于这里的代码来测试存储库类。这段代码测试了 CustomerRepository 类,你可以创建类似的类来测试 OrderRepository 和 ProductRepository 类。

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CRMBIZ;

namespace CRMBIZ.Test
{
    [TestClass]
    public class CustomerRepositoryTest
    {
        [TestMethod]
        public void RetrieveExisting()
        {
            var customerRepository = new CustomerRepository();
            var expected = new Customer(1)
            {
                EmailAddress = "swilliams@greenenergy.com",
                FirstName = "Susan",
                LastName = "Williams"
            };

            var actual = customerRepository.Retrieve(1);

            Assert.AreEqual(expected.CustomerId, actual.CustomerId);
            Assert.AreEqual(expected.EmailAddress, actual.EmailAddress);
            Assert.AreEqual(expected.FirstName, actual.FirstName);
            Assert.AreEqual(expected.LastName, actual.LastName);
        }
    }
}

运行测试是给我们一个大拇指!
C# repository pattern test


CRM应用程序的C#类总结

在本教程中,我们创建了一些类,以便与C#中的CRM类型的应用程序一起工作。一旦创建了这些类,我们就对每个类进行评估,看看我们是否可以简化以减少责任。我们发现我们可以,并将一些逻辑提取到相关的资源库类。采取这种方法可以最大限度地减少耦合,最大限度地提高内聚力,简化维护,并有助于使代码更易测试。我们很快就会看到这些类是如何一起工作的,当我们谈论类之间的关系时。