RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1053952
Accepted
Dmitrii
Dmitrii
Asked:2020-12-04 05:50:05 +0000 UTC2020-12-04 05:50:05 +0000 UTC 2020-12-04 05:50:05 +0000 UTC

为什么需要工厂模式

  • 772

为什么我们需要工厂模式?据我了解,工厂将某个值作为输入,通过它可以确定工厂应该返回哪个类的对象。所有这些返回类都是某些超类的后代或实现一个公共接口。实际上,在工厂内部,通常的 switch case(或类似的东西)使用 new 构造函数选择要创建的对象。

这种方法有什么好处?在网上,我从工厂允许你扩展系统,允许你在一个代码中使用不同的对象等类别中找到了例子。但实际上与通常的多态性相同。那些。如果我创建一个接口或一个超类和几个继承人,那么工厂能带来什么利润?可扩展性、通用性等 提供多态性。写 factory.createClass(classType1) 而不是 new classType1 有什么好处。

шаблоны-проектирования
  • 5 5 个回答
  • 10 Views

5 个回答

  • Voted
  1. AivanF.
    2020-12-04T08:42:10Z2020-12-04T08:42:10Z

    工厂模式相对复杂并且有几个变体。它用于困难的情况,因此很难找到一个简洁且充分的(就有用性而言)示例。

    主要思想是有几个类(具有共同的父/接口)必须创建其对象(可能具有较大的初始化逻辑)并在更远的地方使用,但它们的某些类型和参数是已知的,有些将在稍后出现. 根据该信息,创建工厂对象,将其传递到程序的其他阶段、逻辑部分。在那里,工厂已经接收到其余的参数并构建了必要的对象。也就是说,工厂用于抽象、封装、委托责任。

    重要的是要注意工厂是“手动”创建的:您可以选择任何所需的工厂类型并设置它们的任何设置。在未来的管道中,工厂由对其类型一无所知的代码调用,通过单一接口以相同的方式访问所有工厂。

    关于品种。当只有一个工厂类时,这称为工厂方法模式。当它们有很多并且它们继承自一个公共抽象类时,这就是“抽象工厂”模式。


    假设我们正在开发一个政治行动模拟器。为此,需要政府设施。但它们依赖于意识形态和它们的一些参数(这些是工厂和它们的参数),以及模型参数(将提供给现成工厂的输入)。

    在这种情况下,政府的对象将是你最终需要得到的东西(议会/总统)。工厂的角色将是类意识形态的实例,这些实例将特定于这些意识形态的一些参数作为输入。最后,所有这些都被转移到模型对象中,工厂调用带有最终参数(模拟事件的年份)的通用方法,最终的政府对象已经创建。

    下面是一个 Python 中的抽象工厂的例子,有点麻烦,但就是这样使用工厂的。但是,总的来说,代码很简单:

    class Government:
        def __init__(self, member_count):
            raise AttributeError('Not Implemented!')
    
        def __str__(self):
            return 'Какое-то правительство'
    
        def __repr__(self):
            return self.__str__()
    
    class Parliament(Government):
        def __init__(self, member_count, title=None):
            self.member_count = member_count
            self.title = 'Парламент' if title is None else title
    
        def __str__(self):
            return '%s из %s человек' % (self.title, self.member_count)
    
    class President(Government):
        def __init__(self, reign_years, title=None):
            self.reign_years = reign_years
            self.title = 'Президент' if title is None else title
    
        def __str__(self):
            return '%s на срок %s лет' % (self.title, self.reign_years)
    
    
    # Абстрактная фабрика
    class Ideology:
        def __init__(self):
            raise AttributeError('Not Implemented!')
    
        def __str__(self):
            return 'Какая-то идеология'
    
        def __repr__(self):
            return self.__str__()
    
        def create_goverment(self, year):
            # Сам фабричный метод
            raise AttributeError('Not Implemented!')
    
    class Democracy(Ideology):
        def __init__(self, radical):
            self.radical = radical
    
        def create_goverment(self, year):
            years = 6 if year < 1990 else 4
            title = 'Президент'
            if self.radical:
                years *= 100
                title = 'Монарх'
            return President(years, title)
    
    class Socialism(Ideology):
        def __init__(self, western=True):
            self.western = western
    
        def create_goverment(self, year):
            if not self.western and year >= 1991:
                parliament_title = 'Совет Федерации'
            else:
                parliament_title = 'Парламент'
    
            parliament_member_count = 10
            if year > 1800:
                parliament_member_count = 30
            if not self.western:
                parliament_member_count *= 2
            return Parliament(parliament_member_count, parliament_title)
    
    
    class Model:
        def __init__(self, ideologies, year=1800):
            # Создаём из фабрик объекты через единый интерфейс
            self.governments = [x.create_goverment(year=year) for x in ideologies]
    
        def process(self):
            raise AttributeError('Not Implemented!')
    
        def __str__(self):
            return '\n'.join(['\t Модель правительств:'] + list(map(str, self.governments)))
    
        def __repr__(self):
            return self.__str__()
    
    
    if __name__ == '__main__':
        # Создаём фабрики со специфическими для них параметрами
        ideologies = (
            Democracy(radical=True),
            Democracy(radical=False),
            Socialism(western=True),
            Socialism(western=False),
        )
        # Передаём дальше
        m = Model(ideologies, year=1995)
        print(m)
    
    
    ### Вывод такой:
    #     Модель правительств:
    # Монарх на срок 400 лет
    # Президент на срок 4 лет
    # Парламент из 30 человек
    # Совет Федерации из 60 человек
    
    ## PS: пример взят из воздуха и на полит.корректность совсем не претендует
    

    在实际问题中,代码甚至更大,但在其中使用工厂更加合乎逻辑和有用。

    顺便说一句,在 Python 中,工厂类覆盖__call__. 除了简洁之外,这还允许您平等地使用自己的工厂和类构造函数(毕竟,Python 类是返回最终对象的可调用对象,即类是工厂)。

    有用的链接:

    • enSO:工厂方法和抽象工厂
    • 维基:工厂方法
    • 维基:抽象工厂

    维基百科有更多不同语言的代码示例,以及类图,这将帮助您更好地理解这些设计模式。

    • 2
  2. Best Answer
    Егор Банин
    2020-12-04T20:10:40Z2020-12-04T20:10:40Z

    没有工厂模式。您可能正在撰写有关工厂方法的文章(它的另一个名称是(突然!)构造函数)。使用它的好处是你的类只知道一个构造函数接口,而不是所有可能的接口。

    假设您已经描述了接口Средство_индивидуальной_мобильности和类Электросмокат,并且Моноколесо. 要制造踏板车,您需要两个轮子,一个独轮车。在您的图书馆中,Новые_правила_дорожного_движения 您不会想知道构建这些个人移动辅助设备需要多少个轮子。但是您希望能够实例化它们。怎样成为?有必要描述设计者的单一界面!这将是工厂方法模式。您接收一个方法作为输入(假设它根本不需要参数)并调用它来获取各个移动工具的实例。您根本不会想到该方法将如何创建它们,如果在 2020 年发明了飞行滑板,那么您将不需要重写您的新道路规则。

    很明显фабрика.создайКласс(класТип1)写错了。我们必须写фабрика.создайНеизвестныйМнеКлассИзвестногоМнеИнтерфейса()。

    • 2
  3. Инди Путный
    2020-12-04T19:32:02Z2020-12-04T19:32:02Z

    当调用的结果是指向某个抽象的指针时,这种模式使用起来很方便,实际上工厂隐藏了它创建和初始化的内容和方式,最重要的是,它不给调用代码任何关于实现的知识。

    事实上,你应该对你想做的事情有一个抽象,而不是这个抽象的实现。工厂应该创建并初始化您需要的实现,并返回一个指向创建对象的抽象指针。

    此外,此模式允许您在一个地方收集所有负责创建对象的代码。

    • 1
  4. Mark Shevchenko
    2020-12-04T20:06:31Z2020-12-04T20:06:31Z

    经典文献中没有描述工厂模式。

    GoF 书描述了抽象工厂和工厂方法。在 Internet 上,您可以找到静态工厂和简单工厂。

    看起来您在询问Simple Factory。以下是它可能派上用场的一些示例。

    反序列化

    我们获取一个复杂对象并将其保存为例如 GeoJSON。另一方面,我们正在尝试恢复原始对象。

    { "type": "Point", 
      "coordinates": [30, 10]
    }
    
    { "type": "LineString", 
      "coordinates": [
        [30, 10], [10, 30], [40, 40]
      ]
    }
    

    这里有必要type按属性创建不同类型的对象。该功能可由工厂接管。在具有反射支持或动态类型的语言中,这并不困难。在像 C++ 这样的语言中,您可能必须执行switch您所写的内容。

    生命周期管理

    当您尝试使用依赖反转做一些开箱即用的事情时,这种情况经常发生在 IoC 容器中。假设您有一个无状态的存储库对象。它可以在 IoC 中注册为单例,并且在程序执行期间将存在于单个实例中。它的每个方法都需要一个数据库连接,连接在 Web 请求开始时创建并在结束时释放。然后可以创建连接工厂或返回一个已在请求中创建的实例。以下是它在 Entity Framework 中的样子:

    public class OrderRepository : IOrderRepository
    {
        private readonly DbContextFactory _dbContextFactory;
    
        public OrderRepository(DbContextFactory dbContextFactory)
        {
            _dbContextFactory = dbContextFactory;
        }
    
        public Order GetById(int id)
        {
            using (var dbContext = _dbContextFactory.Create())
            {
                . . .
            }
        }
    }
    

    大量的构造函数参数

    如果创建一个带有很多参数的复杂对象,代码就会变得更加复杂。经常发生不需要所有这些参数的情况。然后工厂可以向您隐藏从您的角度来看不重要的参数,自己填写。

    • 1
  5. mathematicalman
    2020-02-20T02:09:15Z2020-02-20T02:09:15Z

    如果在代码中根据条件创建特定类的对象,则使用简单工厂模式。如果这种情况只发生在一个地方,那么值得记住第一个SOLID原则- 单一职责(Single responsibility)并将用于创建对象的代码段移动到一个新的单独类中。如果多次 - 那么在更少的代码行中利润会更加明显(如果你有一个新的条件if (type='d'),那么它只需要在一个地方添加 - 在工厂中)。

        /* some code */
    
        // classes A,B,C extends interface IType
        IType object;
        if (type = 'a') {
            object = new A();
        } elseif (type = 'b') {
            object = new B();
        } elseif (type = 'c') {
            object = new C();
        }
    
        /* another code */
    
    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5