C#学习(五)——面向对象:接口

一、何为接口?

接口与抽象类类似,仅作为功能声明不作代码实现的语法结构

public interface ICalculator //行业规范接口命名使用一个大写字母I
{
int Calculator();
}

根源上解耦,使系统之间的耦合减到最小

示例代码

Order.cs

public class Order
    {
        public int Id { get; set; }
        public DateTime DatePlaced { get; set; }
        public Shipment Shipment { get; set; }
        public float TotalPrice { get; set; }
        public bool IsShipped { get; set; }
    }

OrderProcessor.cs

public class OrderProcessor
    {
        private readonly IShippingCalculator _shippingCalculator;

        public OrderProcessor(IShippingCalculator shippingCalculator)
        {
            _shippingCalculator = shippingCalculator;

        }

        public void Process(Order order)
        {
            if (order.IsShipped)
                throw new InvalidOperationException("订单已发货");
            order.Shipment = new Shipment
            {
                Cost = _shippingCalculator.CalculateShipping(order),
                ShippingDate = DateTime.Today.AddDays(1)
            };
            order.IsShipped = true;
            Console.WriteLine($"订单#{order.Id}完成,已发货");
        }

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            var order = new Order
            {
                Id = 123,
                DatePlaced = DateTime.Now,
                TotalPrice = 100f
            };

			IShippingCalculator doubleEleven = new DoubleElevenShippingCalculator();
			IShippingCalculator putong = new ShippingCalculator();
			
			var orderProcessor = new OrderProcessor(doubleEleven);
			
			if (DateTime.Now != new DateTime(2024, 11, 11))
			{
			    orderProcessor = new OrderProcessor(putong);
			}

            Console.Read();
        }
    }

Shipment.cs

public class Shipment
    {
        public float Cost { get; set; }
        public DateTime ShippingDate { get; set; }
    }

ShippingCalculator.cs

class ShippingCalculator : IShippingCalculator
    {
        public float CalculateShipping(Order order)
        {
            if (order.TotalPrice < 30f)
                return order.TotalPrice * 0.1f;
            return 0;
        }
    }

DoubleElevenShippingCalculator.cs

class DoubleElevenShippingCalculator : IShippingCalculator
{
	public float CalculateShipping(Order order)
        {
            return 0;
        }
}

IShippingCalculator.cs

public interface IShippingCalculator
{
	public float CalculateShipping(Order order);
}

二、接口与单元测试

添加项目引用后,对OrderProcessor进行测试

[TestClass]
public class OrderProcessorTest
{
	//被测方法_条件_期望结果
	[TestMethod]
	public void Process_OrderUnshipped_SetShippment()
	{
		OrderProcessor order Processor new OrderProcessor(new FakeShippingCalculator());
		Order order = new Order
		{
			Id = 123,
			DatePlaced = DateTime.Now,
			TotalPlace = 100f
		};
		
		orderProcessor.Process(order);

		Assert.AreEqual(order.Shipment.Cost,5);
		Assert.IsTrue(order.IsShipped);
	}

	[TestMethod]
	[ExpectedException(typeof(InvalidOperationException))]
	public void Process_OrderIsShipped_ThrowException()
	{
		OrderProcessor orderProcessor = new OrderProcessor(new FakeShippingCalculator());

		Order order = new Order
		{
			Id = 123,
			DatePlaced = DateTime.Now,
			TotalPlace = 100f,
			IsShipped = true
		};
		
		orderProcessor.Process(order);
	}
}

FakeShippingCalculator.cs

public class FakeShippingCalculator : IShippingCalculator
{
	public float ShippingCalculator(Order order)
	{
		return 5;
	}
}

三、反转控制与依赖注入

.NET的一等公民:依赖注入

  • [ 依赖关系注入(DI-Dependencies Injection)是一种软件设计模式]
  • [ 在类及其依赖项之间实现控制反转(IoC)的技术]
  • [ 可以实现类似系统配置、日志记录和选项模式等功能模块的解耦]

IOC与依赖注入

  • [ 从不同的角度描述同一件事情 ]
  • [ 通过引入IOC容器,实现对象之间的解耦]
  • [ 核心思想:面向接口]

IOC的好处

  • [ 低耦合性 ]
  • [ 标准性]
  • [ 可重复性]

查看之前的main代码,可以看到是先通过接口创建价格计算器,再在订单处理器计算方法中绑定价格计算器,因此二者处于高度依赖关系

		IShippingCalculator doubleEleven = new DoubleElevenShippingCalculator();
		IShippingCalculator putong = new ShippingCalculator();	
		var orderProcessor = new OrderProcessor(doubleEleven);

故使用依赖注入进行解耦
Program.cs

class Program
{
    static void Main(string[] args)
    {
        var order = new Order
        {
            Id = 123,
            DatePlaced = DateTime.Now,
            TotalPrice = 100f
        };

        //配置IOC
        ServiceCollection services = new ServiceCollection();
        //singleton,单例模式
        //scoped,作用域模式
        //tansient,瞬时模式
        //services.AddSingleton<IOrderProcessor, OrderProcessor>();
        //services.AddTransient<IOrderProcessor, OrderProcessor>();
        services.AddScoped<IOrderProcessor, OrderProcessor>();
        services.AddScoped<IShippingCalculator, DoubleElevenShippingCalculator>();

        //从IOC提取服务
        IServiceProvider serviceProvider = services.BuildServiceProvider();
        var orderProcessor = serviceProvider.GetService<IOrderProcessor>();
        var doubleElevenShippingCalculator = serviceProvider.GetService<IShippingCalculator>();

        //处理订单
        orderProcessor.Process(order);
        float freight= doubleElevenShippingCalculator.CalculateShipping(order);
        Console.WriteLine($"运费为{freight}元");

        Console.Read();
    }
}

IOrderProcessor.cs

public interface IOrderProcessor
{
    public void Process(Order order);
}

OrderProcessor.cs

public class OrderProcessor : IOrderProcessor
{
    private readonly IShippingCalculator _shippingCalculator;

    public OrderProcessor(IShippingCalculator shippingCalculator)
    {
        Console.WriteLine("OrderProcesor被创建");
        _shippingCalculator = shippingCalculator;

    }

    public void Process(Order order)
    {
        if (order.IsShipped)
            throw new InvalidOperationException("订单已发货");
        order.Shipment = new Shipment
        {
            Cost = _shippingCalculator.CalculateShipping(order),
            ShippingDate = DateTime.Today.AddDays(1)
        };
        order.IsShipped = true;
        Console.WriteLine($"订单#{order.Id}完成,已发货");
    }
}

DoubleElevenShippingCalculator.cs

class DoubleElevenShippingCalculator : IShippingCalculator
{
    public DoubleElevenShippingCalculator() 
    {
        Console.WriteLine("DoubleElevenShippingCalculator被创建");
    }
    public float CalculateShipping(Order order)
    {
        return 0;
    }
}

四、依赖管理

上述代码使用的是NuGet下的microsoft.extensions.dependencyinjection
microsoft.extensions.dependencyinjection

五、多重继承?多重实现

C#中不存在多重继承!!!!
我们可以在类中实现多重接口,但这不是多重继承

public class UIText : UIBase, IDragable, ICopyable
{
    public void Copy()
    {
        throw new NotImplementedException();
    }

    public void Drag()
    {
        throw new NotImplementedException();
    }

    public void Paste()
    {
        throw new NotImplementedException();
    }
}

public interface IDragable
{
    void Drag();
}

public interface ICopyable
{
    void Copy();
    void Paste();
}
public class UIBase 
{
    public int Size { get; set; }
    public int Position { get; set; }

    public void UIDraw() 
    {
        Console.WriteLine("绘制UI");
    }
}

注意区分继承类与接口的区别,对于继承的类来说,可以实现对于方法的重写,然而对于接口来说,只存在对于方法的实现。事实上接口本身的目的就是为了解耦合,而不是代码的复用。

六、接口与多态

OCP开闭原则
Open for extension, and Closed for modification
Open for extension 对于系统的扩展是开放的
Closed for modification 对于修改是关闭的

代码示例
Program.cs

static void Main(string[] args)
{
    var order = new Order
    {
        Id = 123,
        DatePlaced = DateTime.Now,
        TotalPrice = 30f
    };

    OrderProcessor orderProcessor = new OrderProcessor();

    MailService mailService = new MailService();
    orderProcessor.RigisterNotification(mailService);

    INotification smsService = new SmsMessageService();
    orderProcessor.RigisterNotification(smsService);

    orderProcessor.Process(order);

    Console.Read();
}

Order.cs

public class Order
{
    public int Id { get; set; }
    public DateTime DatePlaced { get; set; }
    public float TotalPrice { get; set; }
    public bool IsShipped { get; set; }
}

OrderProcessor.cs

public class OrderProcessor
{
    private readonly List<INotification> messageServices;


    public OrderProcessor()
    {
        messageServices = new List<INotification>();
    }

    public void RigisterNotification(INotification notification)
    {
        messageServices.Add(notification);
    }

    public void Process(Order order)
    {
        // 处理订单...处理发货...

        // 通知用户收货
        foreach (INotification notification in messageServices)
        {
            notification.Send("订单已发货");
        }
    }

}

MailService.cs

internal class MailService :INotification
{
    public void Send(string message)
    {
        Console.WriteLine("发送EMail"+message);
    }
}

INotification.cs

public interface INotification
{
    public void Send(string message);
}

SmsMessageService.cs

public class SmsMessageService : INotification
{
    public void Send(string message)
    {
        Console.WriteLine("发送短信:"+message);
    }
}
  • 25
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值