封装和接口

Encapsulation and Interfaces

几天来,我一直在 Microsoft 站点上的 .NET 教程中研究和研究这一特定课程。 LINK

正如您可能已经知道的那样,每节课的结尾都有一个 "homework"。 这次我应该用一些新功能升级给定的项目并实现封装和接口。

新功能应包括:

我确实设法添加了其中的大部分功能。我目前的项目(已更新):

namespace ConsoleApp2
{
class Program
{
    static void Main()
    {
        Customer customer1 = new Customer("John");
        Customer customer2 = new Customer("George");
        var customers = new List<Customer>() { customer1, customer2 };
        customer1.AddOrder("car", "12/7/1999"); // will be removed due to same name
        customer1.AddOrder("vase", "20/6/2024");// will not be added to the list because of the future time
        customer1.AddOrder("car", "3/12/2014");
        customer1.AddOrder("headphones", "3/12/2022");// will not be added to the list because of the future time
        customer2.AddOrder("headphones", "10/3/2002");
        customer2.AddOrder("", "");// will not be added to the list due to empty values

        //print customers

        foreach (var customer in customers)
        {
            customer.Print();
        }
    }
}
public class Customer
{
    public string Name { get; }
    private List<Order> orders = new List<Order>();
    private List<Order> ordersHistory = new List<Order>();


    public Customer(string name)
    {
        Name = name;
    }

    public void AddOrder(string name, string date)
    {
        if (name == null) { return; }
        else if (name == "" || date == "") { return; }
        else
        {
            AddHistoricOrder(name, date);
            AddRegularOrder(name, date);
        }


    }
    public void Print()
    {
        Console.WriteLine(Name);
        Console.Write("Orders: ");
        orders.ForEach(Console.Write);
        Console.WriteLine();
        Console.Write("Historic Orders: ");
        ordersHistory.ForEach(Console.Write);
        Console.WriteLine();
        Console.WriteLine($"Order Count: {orders.Count}");
        Console.WriteLine();
        Console.WriteLine();
    }

    private void AddRegularOrder(string name, string date)
    {

        if (DateTime.Parse(date) > DateTime.Now) { return; }
        else
        {

            for (int i = 0; i < orders.Count; i++)
            {
                if (orders[i].OrderName == name)
                {
                    orders.RemoveAt(i);
                }
            }
            orders.Add(new Order(name, date));

        }
    }
    private void AddHistoricOrder(string name, string date)
    {
        ordersHistory.Add(new Order(name, date));
    }
    public override string ToString()
    {
        return $"{Name}";
    }

}
public class Order
{
    public string OrderName { get; }
    public DateTime OrderDate { get; set; }

    public Order(string orderName, string date)
    {
        OrderName = orderName;
        OrderDate = DateTime.Parse(date);;
    }
    public override string ToString()
    {
        return $"{OrderName} ({OrderDate.ToShortDateString()}), ";
    }
}
}

即使我搜索并观看了各种关于封装和接口的视频,我仍然不确定我应该如何在这里实现它们。 你能帮我提高我的代码效率吗?

我没有实施 属性 来公开历史订单(我只是不确定应该做什么)

我也没有真正理解课程中称为 "New is Glue" 的部分,它说我们应该避免在我们的代码中添加新关键字,并展示了一些使用接口的示例。我没有找到给定 LINK 之外的任何信息 我应该如何避免在这个特定项目中创建新实例? 提前致谢!

没有完美的方法来完成某件事,总有更好的方法,所以不要担心拥有完美的代码,尤其是在您刚开始的时候。

我已阅读教程并检查了您的代码,我认为您到目前为止做得很好。

关于 属性 公开历史订单我认为这可以用不同的方式解释,因为它太笼统了。例如,我可以制作另一个列表,添加客户请求的每个订单,而不必担心日期、名称或它是否为空。

另一种方法是添加另一个列表作为主要列表,但如果您添加一个具有相同名称的订单,它将存储它而不删除前一个,因为它是一个历史记录。

你可以这样做。

public class Customer
{
    public string Name { get; }
    private List<Order> orders = new List<Order>();
    public List<Order> historicOrders = new List<Order>();


    public Customer(string name)
    {
        Name = name;
    }

    public void AddOrder(string name, string date)
    {
        if (name == "" || date == "" ) ;
        else if (DateTime.Parse(date) > DateTime.Now) ; 
        else
        {

            for (int i = 0; i < orders.Count; i++)
            {
                if (orders[i].OrderName == name)
                {
                    orders.RemoveAt(i);
                }
            }
            orders.Add(new Order(name, date));
            historicOrders.Add(new Order(name, date));

        }
    }

    public void Print()
    {
        Console.WriteLine(Name);
        Console.Write("Orders: ");
        orders.ForEach(Console.Write);
        Console.WriteLine();
        Console.WriteLine($"Order Count: {orders.Count}");
        Console.WriteLine();
        Console.WriteLine();
    }
    public override string ToString()
    {
        return $"{Name}";
    }

}
  1. 客户有一个 属性 公开他们的历史订单: 只需添加一个 getter 即可显示订单列表。

    public 列表订单 { get;} = new List();

  2. 尝试添加空订单应该什么都不做:

    我认为这里需要的功能是忽略空对象

    public void AddOrder(Order o){  
      if (o == null){  
        return;
      }
    
      //rest of your implememntaton
    }  
    

    您正在使用名称和日期添加订单,而不是尝试传递一个 Order 对象到函数,为简单起见,假设名称是 唯一标识符。

  3. New is Glue

    撇开依赖注入不谈(不管怎样,它现在对你来说只是一个流行词)。

    他们试图强调的是 "new" 关键字创建了一个依赖项 关于您创建的特定 class,您将来是否应该决定 更改负责 order/customer 等的 class。您将不得不 返回您的代码并修改它,可能在多个位置。

    目前,您可以使用的工具有限,您可以做的是 添加一个为您创建对象的函数,即使在 您正在使用的函数 "new".

    例如:

    public Order CreateNewOrder(string name, string date) { return new Order (name, date); }