C# 工厂模式学习
工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的接口,而不是通过具体类来实例化对象。工厂模式可以将对象的创建过程封装起来,使代码更具有灵活性和可扩展性。
工厂模式有几种常见的实现方式:
-
简单工厂模式(Simple Factory Pattern): 简单工厂模式通过一个工厂类来决定创建哪种具体类的实例。这个工厂类通常提供一个静态方法,根据传入的参数创建相应的对象。
-
工厂方法模式(Factory Method Pattern): 工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法使一个类的实例化延迟到其子类。
-
抽象工厂模式(Abstract Factory Pattern): 抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而无需明确指定具体类。通过使用抽象工厂模式,一个类可以实例化一组相关对象,而不需要知道它们的具体类。
简单工厂模式示例
假设我们有一个动物园项目,需要创建不同的动物对象:
// 动物接口 public interface IAnimal { void Speak(); } // 具体的动物类 public class Dog : IAnimal { public void Speak() { Console.WriteLine("Woof!"); } } public class Cat : IAnimal { public void Speak() { Console.WriteLine("Meow!"); } } // 简单工厂类 public static class AnimalFactory { public static IAnimal CreateAnimal(string animalType) { switch (animalType.ToLower()) { case "dog": return new Dog(); case "cat": return new Cat(); default: throw new ArgumentException("Unknown animal type"); } } } // 使用示例 class Program { static void Main(string[] args) { IAnimal animal = AnimalFactory.CreateAnimal("dog"); animal.Speak(); // 输出:Woof! } }
工厂方法模式示例
假设我们有一个动物园项目,不同的子类需要创建不同的动物对象:
// 动物接口 public interface IAnimal { void Speak(); } // 具体的动物类 public class Dog : IAnimal { public void Speak() { Console.WriteLine("Woof!"); } } public class Cat : IAnimal { public void Speak() { Console.WriteLine("Meow!"); } } // 工厂接口 public interface IAnimalFactory { IAnimal CreateAnimal(); } // 具体工厂类 public class DogFactory : IAnimalFactory { public IAnimal CreateAnimal() { return new Dog(); } } public class CatFactory : IAnimalFactory { public IAnimal CreateAnimal() { return new Cat(); } } // 使用示例 class Program { static void Main(string[] args) { IAnimalFactory factory = new DogFactory(); IAnimal animal = factory.CreateAnimal(); animal.Speak(); // 输出:Woof! } }
抽象工厂模式示例
假设我们有一个动物园项目,需要创建一组相关的对象(例如,动物及其食物):
// 动物接口 public interface IAnimal { void Speak(); } // 具体的动物类 public class Dog : IAnimal { public void Speak() { Console.WriteLine("Woof!"); } } public class Cat : IAnimal { public void Speak() { Console.WriteLine("Meow!"); } } // 食物接口 public interface IFood { void Get(); } // 具体的食物类 public class DogFood : IFood { public void Get() { Console.WriteLine("Dog food"); } } public class CatFood : IFood { public void Get() { Console.WriteLine("Cat food"); } } // 抽象工厂接口 public interface IAnimalFactory { IAnimal CreateAnimal(); IFood CreateFood(); } // 具体工厂类 public class DogFactory : IAnimalFactory { public IAnimal CreateAnimal() { return new Dog(); } public IFood CreateFood() { return new DogFood(); } } public class CatFactory : IAnimalFactory { public IAnimal CreateAnimal() { return new Cat(); } public IFood CreateFood() { return new CatFood(); } } // 使用示例 class Program { static void Main(string[] args) { IAnimalFactory factory = new DogFactory(); IAnimal animal = factory.CreateAnimal(); IFood food = factory.CreateFood(); animal.Speak(); // 输出:Woof! food.Get(); // 输出:Dog food } }
以上是三种工厂模式的基本示例,可以根据具体需求选择合适的工厂模式来实现代码的创建和管理。如果希望在增加新动物类型时尽量减少对现有类的修改,推荐使用工厂方法模式。工厂方法模式的设计使得每新增一种动物,只需增加一个对应的工厂类和具体的动物类,而无需修改已有的代码,从而符合开闭原则(即对扩展开放,对修改关闭)。
使用工厂方法模式
下面是一个更完善的工厂方法模式示例,展示了如何在增加新动物时,尽量减少对现有代码的修改。
// 动物接口 public interface IAnimal { void Speak(); } // 具体的动物类 public class Dog : IAnimal { public void Speak() { Console.WriteLine("Woof!"); } } public class Cat : IAnimal { public void Speak() { Console.WriteLine("Meow!"); } } // 新增的动物类 public class Bird : IAnimal { public void Speak() { Console.WriteLine("Tweet!"); } } // 工厂接口 public interface IAnimalFactory { IAnimal CreateAnimal(); } // 具体工厂类 public class DogFactory : IAnimalFactory { public IAnimal CreateAnimal() { return new Dog(); } } public class CatFactory : IAnimalFactory { public IAnimal CreateAnimal() { return new Cat(); } } // 新增的动物工厂类 public class BirdFactory : IAnimalFactory { public IAnimal CreateAnimal() { return new Bird(); } } // 使用示例 class Program { static void Main(string[] args) { List<IAnimalFactory> factories = new List<IAnimalFactory> { new DogFactory(), new CatFactory(), new BirdFactory() // 新增的工厂只需在这里添加 }; foreach (var factory in factories) { IAnimal animal = factory.CreateAnimal(); animal.Speak(); } } }
在这个示例中,新增一种动物只需:
- 创建新的具体动物类,例如
Bird
。 - 创建对应的工厂类,例如
BirdFactory
。 - 在使用的地方添加新的工厂实例,例如在
factories
列表中添加new BirdFactory()
。
这样做的好处是每增加一个新动物类型,不需要修改现有的工厂类或具体的动物类,只需要添加新的类和工厂即可,从而降低了代码修改的风险和复杂度。
使用反射和配置来进一步减少修改
如果希望在增加动物时连代码都不需要改动,可以考虑使用反射和配置文件的方式。通过配置文件定义动物类型和对应的工厂类,然后使用反射动态加载:
// 动物接口和具体的动物类(同上) // 工厂接口和具体工厂类(同上) // 使用反射加载工厂类 class Program { static void Main(string[] args) { // 假设配置文件中定义了动物类型和对应的工厂类 var factoryTypes = new List<string> { "DogFactory", "CatFactory", "BirdFactory" // 配置文件中新增的工厂类 }; var factories = new List<IAnimalFactory>(); foreach (var factoryType in factoryTypes) { var type = Type.GetType(factoryType); if (type != null && typeof(IAnimalFactory).IsAssignableFrom(type)) { var factory = (IAnimalFactory)Activator.CreateInstance(type); factories.Add(factory); } } foreach (var factory in factories) { IAnimal animal = factory.CreateAnimal(); animal.Speak(); } } }
接口与继承结合使用
工厂模式主要使用了接口、继承,在C#中,接口和继承是面向对象编程的重要概念。接口定义了一组方法和属性,而继承允许一个类从另一个类继承其成员。接口可以实现多重继承,而类只能继承一个基类。通常情况下,接口和继承可以结合使用,以充分利用它们各自的优点。通过这种方式,基类可以提供一些通用的实现,而接口可以定义特定的行为。
// 接口 public interface IAnimal { void Speak(); void Eat(); } // 基类 public class Animal { public void Sleep() { Console.WriteLine("Sleeping..."); } } // 派生类实现接口 public class Dog : Animal, IAnimal { public void Speak() { Console.WriteLine("Woof!"); } public void Eat() { Console.WriteLine("Dog is eating."); } } public class Cat : Animal, IAnimal { public void Speak() { Console.WriteLine("Meow!"); } public void Eat() { Console.WriteLine("Cat is eating."); } } // 使用示例 class Program { static void Main(string[] args) { IAnimal dog = new Dog(); dog.Speak(); // 输出:Woof! dog.Eat(); // 输出:Dog is eating. IAnimal cat = new Cat(); cat.Speak(); // 输出:Meow! cat.Eat(); // 输出:Cat is eating. // 使用基类方法 Animal animalDog = (Animal)dog; animalDog.Sleep(); // 输出:Sleeping... Animal animalCat = (Animal)cat; animalCat.Sleep(); // 输出:Sleeping... } }
总结
- 接口:定义了一组必须实现的方法和属性,没有实现代码。支持多重继承,使得类可以实现多个接口。
- 继承:用于从现有类创建新类,继承基类的成员。每个类只能有一个基类,但可以实现多个接口。
- 结合使用:通过将接口和继承结合使用,可以实现代码的高复用性和灵活性。
通过上述示例,可以看到如何使用接口和继承来设计灵活且可扩展的应用程序结构。这样既能充分利用基类的通用功能,又能通过接口实现特定的行为。