设计模式 工厂方法模式

简介: 工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

工厂方法(Factory Method)模式结构图:

角色:

抽象工厂角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
具体工厂角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象
抽象产品角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在上图中,这个角色是Light。
具体产品角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。

上一篇我们使用简单工厂模式实现了:

如果有一个住户管理系统,里面的住户类型是可变的,每一种租户类型的租金计算公式都存在差异
例如:A类型的住户租金额=天数*单价+绩效*0.005;B类型的住户租金额=月份*(每月价格+performance*0.001)
这里我们虽然实现了客户的需求,但是如果客户后期需要增加了C类型商店和D类型商店,而它们的算法要求又不一样,
这个时候我们就需要进行C,D类型商店的创建,并继承Ishop接口,实现里面的方法,
同时还得继续修改工厂类在switc中增加case进行捕捉创建相应的商店对象,一旦出现这样的情况,是不利于程序的扩展性和项目后期的维护性的。
现在使用工厂方法模式可以很好的解决这一问题。不多说上代码。

1.分析:商店有共同的行为特征,都要进行店铺租金计算行为,我们抽象了Ishop ,里面有待实现的计算商店租金方法行为。

    public interface Ishop
    {
        double Getrent(int days, double dayprice, double performance);
    }

2.实现Isho接口里面的方法,创建A,B类型店铺。

    /// <summary>
    /// 继承商店接口,实现里面的行为方法,即算法
    /// </summary>
    public class Ashop:Ishop
    {
        /// <summary>
        /// /// A类型商店租金额,天数*单价+绩效*0.005
        /// </summary>
        /// <param name="days">天数</param>
        /// <param name="dayprice">每天单价</param>
        /// <param name="performance">日平均绩效</param>
        /// <returns></returns>
        public double Getrent(int days, double dayprice, double performance)
        {
            Console.WriteLine("A商店的租金算法");
            return days * dayprice + performance * 0.01;
        }
    }
    /// <summary>
    /// 继承商店接口,实现里面的行为方法,即算法
    /// </summary>
    public class Bshop:Ishop
    {
        /// <summary>
        /// B类型商店的租金=月份*(每月价格+performance*0.001)
        /// </summary>
        /// <param name="month">月数</param>
        /// <param name="monthprice">月单价</param>
        /// <param name="performance">月平均绩效</param>
        /// <returns></returns>
        public double Getrent(int month, double monthprice, double performance)
        {
            Console.WriteLine("B商店的租金算法");
            return month * (monthprice + performance * 0.001);
        }
    }

3.现在考虑在什么情况下创建商店的实体,对不同的商店进行租金计算,并且方便以后的增加和修改。于是我们创建IFactroy接口,里面有待实现的创建商店对象的方法。

    /// <summary>
    /// 工厂类,创建商店类型实体
    /// </summary>
    public interface IFactory
    {
        Ishop CreateShop();
    }

4.现在我们就可以继承自IFactory,实现里面创建对应的商店对象了

    /// <summary>
    /// 继承工厂类,创建A类型商店实体
    /// </summary>
    public class CreateBshop : IFactory
    {
        public Ishop CreateShop()
        {
            return new Ashop();
        }
    }

    /// <summary>
    /// 继承工厂类,创建B类型商店实体
    /// </summary>
    public class CreateAshop : IFactory
    {
        public Ishop CreateShop()
        {
            return new Bshop();
        }
    }

5.之后根据当前的商店类型进行判断,该类型的商店应该进行哪一种算法:

class Program
    {
        static void Main(string[] args)
        {
            string shopname = ConfigurationManager.AppSettings["CreateShopClassName"];
            //shopname为创建商店类名称,此处=CreateAshop
            IFactory af = (IFactory)Assembly.Load("ProductEnity").CreateInstance("ProductEnity." + shopname);
            //第一个ProductEnity是dll的名称,第二个ProductEnity是项目的命名空间。
            Ishop As = af.CreateShop(); double total = As.Getrent(30, 300, 2000); //30 天/100元 日平均绩效为2000 
            Console.WriteLine("该A类型商店的租金为:" + total); 
            
            Console.WriteLine("=============");
            IFactory bf = (IFactory)Assembly.Load("ProductEnity").CreateInstance("ProductEnity." + "CreateBshop");
            //CreateBshop可以保存为配置或者存在数据库中,
            //注意该保存字符串应该与项目中创建的类名一样,
            //否则反射的方式会找不到该项目下的类。
            Ishop Bs = bf.CreateShop(); total = Bs.Getrent(30, 300, 2000); //30 天/100元 日平均绩效为2000
            Console.WriteLine("该A类型商店的租金为:" + total);
        }
    }

使用反射的方式创建对象,替换了之前的工厂类通过switch创建对象的方式,有利于后面的新类型商店增加和算法修改增加和维护,以后在项目需求在有变革,我们只需要重新在项目中增加C,D类型商店,继承Ishop实现里面的方法,同时,添加继承IFactroy接口,创建对应的商店对象编译该项目的ProductEnity.dll,以后再进行计算该C,D类型的商店算法就可以通过反射的方式进行计算,不需要修改原来的工程类代码。

 

博客内容仅代表个人观点,如发现阐述有误,麻烦指正,谢谢!
目录
相关文章
|
6天前
|
设计模式 前端开发 搜索推荐
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
|
2月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
4月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
2月前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###
|
2月前
|
设计模式 安全 Java
Kotlin - 改良设计模式 - 构建者模式
Kotlin - 改良设计模式 - 构建者模式
|
2月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
46 1
|
3月前
|
设计模式 Java Kotlin
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
本教程详细讲解Kotlin语法,适合希望深入了解Kotlin的开发者。对于快速学习Kotlin语法,推荐查看“简洁”系列教程。本文重点介绍了构建者模式在Kotlin中的应用与改良,包括如何使用具名可选参数简化复杂对象的创建过程,以及如何在初始化代码块中对参数进行约束和校验。
34 3
|
4月前
|
设计模式 算法 安全
设计模式——模板模式
模板方法模式、钩子方法、Spring源码AbstractApplicationContext类用到的模板方法
设计模式——模板模式
|
4月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:如何提高代码的可维护性与扩展性在软件开发领域,PHP 是一种广泛使用的服务器端脚本语言。随着项目规模的扩大和复杂性的增加,保持代码的可维护性和可扩展性变得越来越重要。本文将探讨 PHP 中的设计模式,并通过实例展示如何应用这些模式来提高代码质量。
设计模式是经过验证的解决软件设计问题的方法。它们不是具体的代码,而是一种编码和设计经验的总结。在PHP开发中,合理地使用设计模式可以显著提高代码的可维护性、复用性和扩展性。本文将介绍几种常见的设计模式,包括单例模式、工厂模式和观察者模式,并通过具体的例子展示如何在PHP项目中应用这些模式。
|
4月前
|
设计模式 Java Spring
spring源码设计模式分析-代理设计模式(二)
spring源码设计模式分析-代理设计模式(二)