c#让不同的工厂生产不同的“鸭肉”

任务目标

实现对周黑鸭工厂的产品生产统一管理,主要产品包括鸭脖和鸭翅。武汉工厂能生生产鸭脖和鸭翅,南京工厂只能生产鸭翅,长沙工厂只能生产鸭脖。

分析任务

我们需要有武汉工厂、南京工厂、长沙工厂的类,类中需要实现生产鸭肉的函数,既然都有这个生产鸭肉的函数,我们就可以用接口来限定它。

我们还需要在周黑鸭总部下达生产的命令后,各个工厂都开始生产各自的产品,那么怎么做到让这些函数同时被执行呢?这时我们可以用委托。

前置任务

掌握c#接口和委托的使用

一、接口

在C#中,接口(interface)是一种定义了一套方法和属性但不包含实现的类型。接口规定了一个类必须实现哪些方法和属性,但它不定义这些方法和属性的具体执行内容。接口是抽象类型,不能被实例化。它们通常用于定义对象之间的协议或为不同类提供一个公共的功能接口。

例如:

csharp 复制代码
// 定义一个接口  
public interface IAnimal  
{  
    void Eat();  
    void Sleep();  
}  
  
// 一个类实现该接口  
public class Dog : IAnimal  
{  
    public void Eat()  
    {  
        Console.WriteLine("Dog is eating.");
    }  
  
    public void Sleep()  
    {  
        Console.WriteLine("Dog is sleeping.");  
    }  
}  

Dog类在继承了接口IAnimal接口后必须对其方法进行实现。

  1. 定义契约和行为:

    接口定义了一组方法、属性、事件或其他成员的契约,任何实现该接口的类都必须遵循这些约定。这确保了所有实现该接口的类都具有一致的行为和特征。

  2. 解耦和抽象:

    接口允许我们将类与其具体实现分离,从而实现更高级别的抽象。这使得代码更加模块化,易于维护和扩展。通过将实现细节隐藏在接口后面,我们可以降低类之间的耦合度,提高代码的可重用性。

  3. 多态性支持:

    通过接口,我们可以创建引用不同类型对象的变量,只要这些类型都实现了相同的接口。这使得我们可以在不修改现有代码的情况下,将不同的类互换使用。多态性不仅提高了代码的灵活性,还使得程序更加易于扩展和修改。

  4. 多重继承的一种形式:

    虽然C#不支持类的多重继承(即一个类不能继承自多个基类),但接口允许实现多重继承的效果。一个类可以实现多个接口,从而继承多个接口中的方法、属性等成员。这有助于组合不同的功能集,实现更复杂的业务逻辑。

  5. 插件式架构和框架设计:

    接口在构建插件式架构和框架时非常有用。通过定义一系列接口,我们可以允许第三方开发者创建自己的实现,并将其集成到我们的系统中。这种灵活性使得框架更加开放和可扩展。

  6. 代码清晰和可读性:

    使用接口可以使代码更加清晰和易于理解。通过将相关的方法组织到接口中,我们可以更好地描述类的职责和功能。此外,接口还可以作为文档的一部分,帮助其他开发者理解如何使用我们的类和方法。

  7. 版本控制和兼容性:

    当需要修改现有类的行为时,如果该类实现了接口,我们可以创建一个新的类来实现相同的接口,并在需要时替换旧类。这样,我们可以保持与现有代码的兼容性,同时引入新的功能或修改现有功能。

关于本题,我们可以定义一个IProductionFactory 接口类,里面设置生产方法,然后让所有的工厂类去继承这个接口,并实现其生产方法

二、委托

委托(delegate)在C#编程中是一种特殊的类型,它表示对具有特定参数列表和返回类型的方法的引用。委托的主要用途是将方法作为参数传递给其他方法,或者异步地调用方法。通过使用委托,可以实现回调函数、事件处理、异步编程等多种功能。

具体来说,委托定义了一种方法的签名,并且可以与具有相同签名的方法相关联。一旦委托与某个方法关联,委托就可以被用来调用该方法,就好像委托本身就是一个方法一样。这使得在运行时动态地改变方法的调用成为可能。

  1. 委托用作回调函数来使:
    首先,定义一个委托类型,它接受一个整数数组和一个整数索引(用于返回最大数的位置),并返回最大数:
csharp 复制代码
public delegate int FindMaxDelegate(int[] numbers, out int maxIndex);

然后,创建几个实现这个委托的方法。这些方法将按照不同的逻辑来查找最大数:

csharp 复制代码
public class MaxFinder  
{  
    // 查找数组中的最大数(线性搜索)  
    public static int FindMaxLinear(int[] numbers, out int maxIndex)  
    {  
        int max = numbers[0];  
        maxIndex = 0;  
        for (int i = 1; i < numbers.Length; i++)  
        {  
            if (numbers[i] > max)  
            {  
                max = numbers[i];  
                maxIndex = i;  
            }  
        }  
        return max;  
    }  
  
    // 另一个方法可能使用更高效的算法,这里只是为了演示  
    // (注意:这个示例方法并没有比线性搜索更高效,只是为了演示多个实现)  
    public static int FindMaxDummy(int[] numbers, out int maxIndex)  
    {  
        // 假设这里有一个更复杂的算法来找到最大数...  
        // 但为了简单起见,我们只是返回第一个元素  
        maxIndex = 0;  
        return numbers[0];  
    }  
}

现在,你可以创建一个方法,它接受一个整数数组和一个FindMaxDelegate委托作为参数,并使用这个委托来查找最大数:

csharp 复制代码
public class Program  
{  
    static void Main(string[] args)  
    {  
        int[] numbers = { 1, 3, 7, 2, 9, 5 };  
        FindMaxDelegate findMaxDelegate = MaxFinder.FindMaxLinear; // 使用线性搜索方法  
  
        // 使用委托来查找最大数  
        int max = FindMaxUsingDelegate(numbers, findMaxDelegate);  
        int maxIndex;  
        findMaxDelegate(numbers, out maxIndex); // 也可以直接使用委托获取最大数的索引  
  
        Console.WriteLine("Max number is: " + max);  
        Console.WriteLine("Max number index is: " + maxIndex);  
    }  
  
    static int FindMaxUsingDelegate(int[] numbers, FindMaxDelegate findMax)  
    {  
        int maxIndex;  
        return findMax(numbers, out maxIndex);  
    }  
}

程序将输出:
Max number is: 9
Max number index is: 4

  1. 委托用于多播调用
    什么是多播调用?
    委托可以添加多个函数地址,当调用委托时,这些函数都会被执行
    但是如果函数有返回值,那么委托只会返回最后一个被添加进委托的函数的返回值

例如我们可以实现一个计算器委托

csharp 复制代码
delegate T Calculate<T>(T x,T y);

注:委托是实现成泛型模板的

建一个数学类,里面有加减两种方法:

csharp 复制代码
    class Math
    {
        public int add(int x, int y) { return x + y; }
        public int sub(int x, int y) { return x - y; }
    }

addsub添加进委托中,调用委托

csharp 复制代码
    internal class Program
    {
        static void Main(string[] args)
        {
            Math math = new Math();
            Calculate<int> cal = math.add;
            cal += math.sub;
            Console.WriteLine(cal(1, 2).ToString());
        }
    }

通过调试可以知道,在调用委托后,addsub都被执行了

但是显示在终端的只有 -1sub的返回值,==因为sub是最后被添加进委托的。

三、完成任务

有了前面这些知识,我们便可以实现生产周黑鸭的功能了。

  1. 定义生产接口
csharp 复制代码
public interface IProductionFactory 
{
	//其他函数...
    void produce();
}
  1. 定义工厂类,并实现生产方法
csharp 复制代码
public class WuhanFactory : IProductionFactory
{
    public void produce()
    {
       	//具体方法...
        Console.WriteLine("生产鸭脖和鸭翅");
    }
}
public class NanjingFactory : IProductionFactory
{
    public void produce()
    {
    	//具体方法...
        Console.WriteLine("生产鸭翅");
    }
}
public class ChangshaFactory : IProductionFactory
{
    public void produce()
    {
        //具体方法...
        Console.WriteLine("生产鸭脖");
    }
}
  1. 定义委托
csharp 复制代码
 delegate void ProductionDelegate();
  1. 实例化各个工厂,并加其生产方法添加进委托,调用委托即可实现让所有工厂生产。
csharp 复制代码
 static void Main(string[] args)
 {
     WuhanFactory factory1 = new WuhanFactory();
     NanjingFactory factory2 = new NanjingFactory();
     ChangshaFactory factory3 = new ChangshaFactory();
     ProductionDelegate produce = factory1.produce;
     produce += factory2.produce;
     produce += factory3.produce;
     produce(); }
相关推荐
hopetomorrow5 分钟前
学习路之PHP--使用GROUP BY 发生错误 SELECT list is not in GROUP BY clause .......... 解决
开发语言·学习·php
小牛itbull15 分钟前
ReactPress vs VuePress vs WordPress
开发语言·javascript·reactpress
广煜永不挂科22 分钟前
Devexpress.Dashboard的调用二义性
c#·express
请叫我欧皇i23 分钟前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
闲暇部落26 分钟前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
GIS瞧葩菜35 分钟前
局部修改3dtiles子模型的位置。
开发语言·javascript·ecmascript
chnming198740 分钟前
STL关联式容器之set
开发语言·c++
熬夜学编程的小王1 小时前
【C++篇】深度解析 C++ List 容器:底层设计与实现揭秘
开发语言·数据结构·c++·stl·list
GIS 数据栈1 小时前
每日一书 《基于ArcGIS的Python编程秘笈》
开发语言·python·arcgis
Mr.131 小时前
什么是 C++ 中的初始化列表?它的作用是什么?初始化列表和在构造函数体内赋值有什么区别?
开发语言·c++