java 开关飞行模式_没有开关的工厂模式,这就是应该如何做

java 开关飞行模式

重点 (Top highlight)

应用的设计模式:工厂 (APPLIED DESIGN PATTERNS: Factory)

You’ve come to the right place if you’re struggling with the factory pattern or wondering how to create a factory class without switching and if-else statements.

如果您在工厂模式中苦苦挣扎,或者想知道如何在不切换和if-else语句的情况下创建工厂类,那么您来对地方了。

From the sheer number of StackOverflow posts regarding this, I can tell you are not alone.

从与此有关的大量StackOverflow帖子中,我可以告诉您,并不孤单。

I’ll drop my 2 cents on how you can implement the factory pattern without any use of code branching. I think you’ll find my approach helpful as it provides you something I couldn’t easily get an answer for back when I was a beginner.

我将花费2美分,介绍如何无需任何代码分支即可实现工厂模式。 我认为您会发现我的方法很有用,因为它为您提供了一些我刚入门时无法轻易得到的答案。

让我们先了解一下背景 (Let’s get some context first)

The factory pattern is one of those very fundamental patterns I’m almost sure every developer ever has heard of. I won’t preach theory, so in the unlikely event you haven’t heard of the factory pattern, go do some quick research and get back here.

我几乎可以肯定,每个开发人员都听说过,工厂模式是这些非常基本的模式之一。 我不会讲理论,所以在您不太可能听说过工厂模式的情况下,请进行一些快速研究,然后再回到这里。

The vast amount of tutorials showcases some mind-numbing, hard-to-extend, factory based on branching logic.

大量的教程展示了一些基于分支逻辑的令人麻木的,难以扩展的工厂。

The issue with logical statements such as switch and if-else in a factory class is whenever you’re developing some new type it should be able to create, you’ll have to modify the factory itself.

工厂类中的诸如switch和if-else之类的逻辑语句的问题是,每当您开发它应该能够创建的某种新类型时,都必须修改工厂本身。

This clearly violates the Open/Closes principle.

这显然违反了打开/关闭原则。

什么时候可以考虑更好的方法? (When is an approach considered better?)

We might have different interpretations of what’s great.

我们可能会对美好之处有不同的解释。

Some developers — often more junior ones — prefer if-else above all else. It’s insanely easy to implement and it’s performant. For a very simple and small codebase, a factory implemented with logical statements might be tolerable.

一些开发人员(通常是初级人员)更喜欢if-else。 它非常容易实现且性能出色。 对于非常简单和小的代码库,使用逻辑语句实现的工厂可能是可以容忍的。

To me, great code is easy to read, extend, and maintain. We achieve all this following the approach I’m about to show you.

对我来说, 出色的代码易于阅读,扩展和维护。 我们将按照我将向您展示的方法来实现所有这些目标。

“已经告诉我解决方案了!” (“Show me the solution already!”)

I’ll show an example that might be slightly contrived due to its extreme simplicity, but it serves to demonstrate the different parts of a factory class and its use.

我将展示一个示例,该示例由于其极端的简单性而可能会有些许虚构,但它可以用来演示工厂类的不同部分及其用法。

I can’t anticipate all your needs. I’ll make this generic enough for anyone to get the point, and you’ll then need to apply your requirements to it.

我无法满足您的所有需求。 我将使这个通用名称足够使任何人都明白这一点,然后您需要对它应用您的要求。

Okay… I’ll quit beating around the bush and finally get into it.

好吧……我会放弃在灌木丛中跳动,最后进入它。

So, for this demonstration, we’re going to create a car factory, as I suppose everyone can imagine what that’d be like.

因此,对于这个演示,我们将创建一个汽车工厂,因为我想每个人都可以想象会是什么样子。

Basic classes the factory is going to create
Basic classes the factory is going to create
工厂将要创建的基础课程

We have an abstractCar base class and a few classes implementing the Car class. Nothing fancy.

我们有一个抽象的Car基类和一些实现Car类的类。 没有什么花哨。

What you’ve come for is this code snippet below. Take whatever time you need to read it. I’ll walk you thru how it works afterward.

您追求的是下面的代码片段。 花点时间阅读。 之后,我将指导您。

Extensible factory class without logical statements such as if-else and switch
Extensible factory class without logical statements such as if-else and switch
可扩展的工厂类,没有逻辑语句,例如if-else和switch

To make our factory extensible, we’ll use a private dictionary to hold all possible types we can create. Adding new car types is as easy as calling the RegisterCar method, providing a key called ‘carType’ and a function returning a Car type.

为了使工厂可扩展,我们将使用私有字典来保存我们可以创建的所有可能的类型。 添加新的汽车类型就像调用RegisterCar方法一样容易,它提供了一个名为“ carType”的键和一个返回Car类型的函数。

We see the ‘factoryMethod’ is stored at the end of ‘RegisterCar’. This allows us to configure the factory from somewhere else, e.g. at application startup.

我们看到“ factoryMethod”存储在“ RegisterCar”的末尾。 这使我们可以从其他地方(例如在应用程序启动时)配置工厂。

Then, we have two ways of creating a car. Either by using the Indexer on the factory object, or, by using the CreateCar method. Both are equally valid options.

然后,我们有两种创建汽车的方法。 通过在工厂对象上使用索引器,或通过使用CreateCar方法。 两者都是同等有效的选择。

让我们对其进行测试。 (Let’s put it to the test.)

We’re creating a small test to validate the factory class creates an object of the correct type.

我们正在创建一个小型测试,以验证工厂类是否创建了正确类型的对象。

A simple test that verifies our factory class works
A simple test that verifies our factory class works
一个简单的测试,可以验证我们的工厂级作品

I’m using the xUnit test framework for .NET. This framework has a pretty handy feature called Theory which allows us to define a single test and provide it with multiple data sets thru the [InlineData] attribute.

我正在使用.NET的xUnit测试框架。 该框架具有一个非常方便的功能,称为“理论”,可让我们定义单个测试并通过[InlineData]属性为其提供多个数据集。

Tests pass and everyone’s happy.

测试通过,每个人都很高兴。

让我们通过Web应用程序进行连接 (Let’s wire it up with a web application)

Fine, we got a CarFactory now. It’s all nice and dandy but how do we use this in a real web application?

很好,我们现在有了CarFactory。 一切都很好,但是我们如何在真实的Web应用程序中使用它呢?

First, we’ll need to register our factory class with the dependency injection framework. I’ll be using the standard Microsoft DI framework provided to us out of the box.

首先,我们需要使用依赖项注入框架注册我们的工厂类。 我将立即使用提供给我们的标准Microsoft DI框架。

Here, IServiceCollection is basically the DI container. I’m sure your DI framework of choice has something similar.

在这里, IServiceCollection基本上是DI容器。 我确定您选择的DI框架也有类似的东西。

Registering the factory class with the dependency injection framework
Registering the factory class with the dependency injection framework
使用依赖项注入框架注册工厂类

Whenever another class takes a CarFactory as a constructor argument, it receives an instance configured with three registered car types as shown above.

每当另一个类将CarFactory作为构造函数参数时,它都会收到一个实例,该实例配置有三种注册的汽车类型,如上所示。

Using our factory in a web controller is as easy as letting the controller have a dependency on CarFactory and then just use its methods. It’s all wired up already.

在Web控制器中使用我们的工厂就像让控制器依赖于CarFactory然后仅使用其方法一样简单。 全部都已经连接好了。

Simple controller using the Factory Class
Simple controller using the Factory Class
使用工厂类的简单控制器

At this point, making a request to api/cars returns["Mercedes-A180", "Audi-A5", "Audi-A5-Convertible"].

此时,向api/cars请求将返回["Mercedes-A180", "Audi-A5", "Audi-A5-Convertible"]

A request to api/cars/Audi-A5 returns a JSON serialized version of our Audi A5 registration:{ "model": "A5" }.

api/cars/Audi-A5的请求将返回我们的Audi A5注册的JSON序列化版本: { "model": "A5" }

向工厂添加新的类很容易 (Adding new classes to the factory is easy)

You’ll just need to register an object with an associated key when you register the factory with the dependency framework, and that’s it.

当您在依赖框架中注册工厂时,只需要将对象与关联的键一起注册即可。

There’s no a whole lot more to this point.

到目前为止,还没有更多。

表现如何? (What’s performance like?)

I did a simple performance test to get a better understanding of how performant a factory class in relation to using a switch.

我做了一个简单的性能测试,以更好地了解与使用开关有关的工厂类性能。

In the test itself, I’m just instantiating a Car based on a string provided to either the switch or factory class. The time in milliseconds is the accumulated time of doing 1 million iterations.

在测试本身中,我只是基于提供给switch或factory类的字符串实例化Car。 以毫秒为单位的时间是执行一百万次迭代的累积时间。

Tests are run on a MacBook Pro 2015 model 2.5 GHz with 16GB 1600 MHz DDR3 RAM.

测试在配备16GB 1600 MHz DDR3 RAM的MacBook Pro 2015型号2.5 GHz上运行。

Performance table of doing 1 million iterations
Performance table of doing 1 million iterations
执行一百万次迭代的性能表

The switch test is as you expect. We’re basically just having a switch statement that picks the car type to instantiate. That’s likely the typical factory class implementation you’re used to seeing.

开关测试符合您的预期。 我们基本上只有一个switch语句,它选择要实例化的汽车类型。 这可能是您惯常看到的典型工厂类实现。

Factory1 test is conducted in a way that for each iteration, the factory class is instantiated and 3 car types are registered with it. Then, as in the switch, a Car type is instantiated based on string input.

进行Factory1测试的方式是,对于每次迭代,实例化factory类并向其注册3种汽车类型。 然后,如在开关中一样,基于字符串输入实例化Car类型。

Factory2 test is much like the previous test. However, the major difference is the factory class is only instantiated once with its 3 car types registered. Then, a Car type is instantiated based on string input.

Factory2测试非常类似于先前的测试。 但是,主要的区别是工厂类仅在注册了3种汽车类型的情况下实例化一次。 然后,基于字符串输入实例化Car类型。

我们也可以使用反射 (We can also use reflection)

My approach will still require you to manually go register a new Car type with our factory object. If you want to avoid this, you’ll need to do some reflection work.

我的方法仍然需要您手动向我们的工厂对象注册新的汽车类型。 如果要避免这种情况,则需要做一些反思工作。

Reflection is a great tool when you want your code to be extremely flexible and extensible. However, it’s outside the scope of this article. I’d just like to let you know that’s also a viable option.

当您希望代码非常灵活和可扩展时,反射是一个很好的工具。 但是,这不在本文的讨论范围之内。 我只想告诉您这也是一个可行的选择。

Resources for the curious
-------------------------Factory Pattern by oodesign.com
Image for post
Image for post

Nicklas Millard is a software development engineer in one of the fastest-growing banks, building mission-critical financial services infrastructure.

Nicklas Millard是发展最快的银行之一的软件开发工程师,负责构建关键任务金融服务基础架构。

Previously, he was a Big4 Senior Tech Consultant developing software for commercial clients and government institutions.

在此之前,他是Big4高级技术顾问,为商业客户和政府机构开发软件。

Connect on LinkedIn

LinkedIn上连接

翻译自: https://medium.com/swlh/factory-pattern-without-switch-this-is-how-it-should-be-done-cd895e356f44

java 开关飞行模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值