要探索如何在实践中应用坚实的原则,让我们创建一个故事。
开始
认识穆罕默德(Mohammad),他想建立一个强大的支付系统。
首先,穆罕默德计划创建一个具有多个职责的类,例如添加项目,计算价格,创建验证过程以及使用不同的方法接受付款。
系统初始代码:
class Order:
items = []
quantities = []
prices = []
status = "open"
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
def pay(self, payment_type, security_code):
if payment_type == "debit":
print("Processing payment type...")
print(f"Verifying code: {security_code}.")
self.status = "paid"
elif payment_type == "credit":
print("Processing payment type...")
print(f"Verifying code: {security_code}.")
self.status = "paid"
else:
raise Exception(f"#### Unknown type: {payment_type}.")
要在代码中使用此类,穆罕默德创建了此用例:
# Making orders
order = Order()
order.add_item("Clean Architecture Book, Uncle Bob", 1, 100)
order.add_item("Speaker", 1, 30)
order.add_item("HDMI Cable", 3, 10)
order.add_item("PIR Sensor", 2, 7)
print(order.total_price())
# Payment using Debit card
order.pay("debit", "123456789")
输出:
174
Processing payment type...
Verifying code: 123456789.
一切正常,穆罕默德目前感到满意。
坚实的原则
让我们假设顾问“ 叔叔清洁”正在帮助穆罕默德在其计划中实施坚实的原则。
实心代表:
- s :单一责任原则。
- o :打开关闭原理。
- l :liskov替代原则。
- i :接口隔离原理。
- d :依赖性反转原理。
1-单一责任原则(SRP)
穆罕默德在其代码中询问了Order
类的责任,并确定它具有多个职责,包括添加项目,计算总价和处理付款详细信息。
现场清洁叔叔
清洁叔叔:嗨,穆罕默德,您听说过SRP吗?
穆罕默德:不,什么是SRP?
清洁叔叔:SRP(代表单一责任原则)指出类只有一个改变的理由。如果您的班级包含多种变更原因;然后表明您的代码紧密耦合,并且更难维护。
穆罕默德:就我而言,这意味着什么?
清洁叔叔:如果新客户要求采用新的付款方式,例如比特币或贝宝(Paypal)怎么办?在这种情况下,您需要修改Order
类。因此,建议将付款责任与Order
类分开。
在此建议之后,穆罕默德将代码更改为以下:
class Order:
items = []
quantities = []
prices = []
status = "open"
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
class PaymentHandler:
def pay_debit(self, order: Order, security_code):
print("Processing Debit Card payment...")
print(f"Verifying code: {security_code}.")
order.status = "paid"
def pay_credit(self, order: Order, security_code):
print("Processing Credit Card payment...")
print(f"Verifying code: {security_code}.")
order.status = "paid"
# Making orders
order = Order()
order.add_item("Clean Architecture Book, Uncle Bob", 1, 100)
order.add_item("Speaker", 1, 30)
order.add_item("HDMI Cable", 3, 10)
order.add_item("PIR Sensor", 2, 7)
print(order.total_price())
# Payment using Credit card
payment_handler = PaymentHandler()
payment_handler.pay_credit(order, "543219876")
输出:
174
Processing Credit Card payment...
Verifying code: 543219876.
清洁叔叔:好工作,穆罕默德!你做得很好。仍然有优化的空间,例如创建一种更改订单状态的特定方法,但就目前而言,这已经足够了。
[有关SRP的更多详细信息,请在here上查看Bob叔叔的博客]
2-开放/关闭原则(OCP)
几天后,一位新客户询问穆罕默德(Mohammad)他的计划是否支持贝宝付款。穆罕默德回答说,可以很容易地添加此功能。
为此,穆罕默德(Mohammad)为贝宝(Paypal)创建了一种新方法,但他在称呼它时犯了一个错误,他使用了pay_debit
而不是使用pay_PayPal
。穆罕默德(Mohammad
现场清洁叔叔
清洁叔叔:嗨,穆罕默德,在审查了您在尝试整合新付款方式时遇到的最近困难之后,我的建议是在您继续开发代码时考虑OCP。
穆罕默德:什么是OCP?
清洁叔叔:OCP代表开放/封闭原则(OCP),该原则指出软件实体(类,函数,...)应为扩展而打开,但是封闭的修改。这意味着,当出现新要求或需要进行更改时,应该可以扩展软件实体的行为而不修改其源代码。
现在考虑到OCP后,新代码变成了:
from abc import ABC, abstractmethod
class Order:
items = []
quantities = []
prices = []
status = "open"
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
class PaymentHandler(ABC):
@abstractmethod
def pay(self, order: Order, security_code):
pass
class DebitPaymentHandler(PaymentHandler):
def pay(self, order: Order, security_code):
print("Processing Debit Card payment...")
print(f"Verifying code: {security_code}.")
order.status = "paid"
class CreditPaymentHandler(PaymentHandler):
def pay(self, order: Order, security_code):
print("Processing Credit Card payment...")
print(f"Verifying code: {security_code}.")
order.status = "paid"
class PayPalPaymentHandler(PaymentHandler):
def pay(self, order: Order, security_code):
print("Processing PayPal payment...")
print(f"Verifying code: {security_code}.")
order.status = "paid"
# Making orders
order = Order()
order.add_item("The Pragmatic Programmer Book, Andy Hunt", 1, 130)
order.add_item("micro:bit Controller", 5, 14)
print(order.total_price())
# Payment using PayPal
paypal_payment = PayPalPaymentHandler()
paypal_payment.pay(order, "543219876")
输出:
200
Processing PayPal payment...
Verifying code: 543219876.
3- liskov替代原理(LSP)
第二天添加PayPal付款集成后,一个名为Mohammad的客户,并告诉他系统中存在一个大问题!要使用PayPal付款,您不需要安全代码。相反,您只需要提供电子邮件地址。
Mohammad考虑将security_code
更改为email
,但这将使用需要security_code
的其他付款方式创建一个新问题。
现场清洁叔叔
清洁叔叔:嘿,穆罕默德,我听说过您的最后一个问题,为什么您不会使用Liskov?
穆罕默德:嘿,叔叔,你在说什么? liskov ???
清洁叔叔:
LSP由代表 liskov替代原则的Barbara Liskov教授创建,该原理 指出,超级类的对象应在不破坏程序行为的情况下替换为其子类的对象。
。在代码库上应用Liskov替代原则的结果是:
from abc import ABC, abstractmethod
class Order:
items = []
quantities = []
prices = []
status = "open"
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
class PaymentHandler(ABC):
@abstractmethod
def pay(self, order: Order):
pass
class DebitPaymentHandler(PaymentHandler):
def __init__(self, security_code):
self.security_code = security_code
def pay(self, order: Order):
print("Processing Debit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class CreditPaymentHandler(PaymentHandler):
def __init__(self, security_code):
self.security_code = security_code
def pay(self, order: Order):
print("Processing Credit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class PayPalPaymentHandler(PaymentHandler):
def __init__(self, email) -> None:
self.email = email
def pay(self, order: Order):
print("Processing PayPal payment...")
print(f"Verifying email: {self.email}.")
order.status = "paid"
# Making orders
order = Order()
order.add_item("The Pragmatic Programmer Book, Andy Hunt", 1, 130)
order.add_item("micro:bit Controller", 5, 14)
print(order.total_price())
# Payment using PayPal
paypal_payment = PayPalPaymentHandler("hi@customer.com")
paypal_payment.pay(order)
输出:
200
Processing PayPal payment...
Verifying email: hi@customer.com.
4-接口隔离原理(ISP)
一段时间后,穆罕默德(Mohammad
该网络安全专家在其报告中提到的要点之一是:向系统添加2FA(两因素身份验证)。
基于此,Mohammad通过在PaymentHandler
中使用SMS auth_2fa_sms
添加身份验证方法开始在此功能上工作。他将其实施给了从基类继承的其他类。
代码如下:
from abc import ABC, abstractmethod
class Order:
items = []
quantities = []
prices = []
status = "open"
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
class PaymentHandler(ABC):
@abstractmethod
def auth_2fa_sms(self, code):
pass
@abstractmethod
def pay(self, order: Order):
pass
class DebitPaymentHandler(PaymentHandler):
def __init__(self, security_code):
self.security_code = security_code
self.verified = False
def auth_2fa_sms(self, code):
print(f"Verifying 2FA using SMS code: {code}")
self.verified = True
def pay(self, order: Order):
if not self.verified:
raise Exception("Not authenticated")
print("Processing Debit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class CreditPaymentHandler(PaymentHandler):
def __init__(self, security_code):
self.security_code = security_code
def auth_2fa_sms(self, code):
# It is also a violation for Liskov Substitution principle
raise Exception(
"Credit card payment doesn't support SMS code authentication.")
def pay(self, order: Order):
print("Processing Credit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class PayPalPaymentHandler(PaymentHandler):
def __init__(self, email) -> None:
self.email = email
def auth_2fa_sms(self, code):
print(f"Verifying 2FA using SMS code: {code}")
self.verified = True
def pay(self, order: Order):
if not self.verified:
raise Exception("Not authenticated")
print("Processing PayPal payment...")
print(f"Verifying email: {self.email}.")
order.status = "paid"
# Making orders
order = Order()
order.add_item("Head First Object Oriented Analysis and Design Book", 1, 76)
order.add_item("Raspberry Pi Camera v2", 2, 40)
print(order.total_price())
# Payment using Debit Card
debit_payment = DebitPaymentHandler("67891")
debit_payment.auth_2fa_sms("54321")
debit_payment.pay(order)
与上述代码中一样,当用户使用借记卡付款时,应在付款过程之前对其进行认证,预期结果将如下:
156
Verifying 2FA using SMS code: 54321
Processing Debit Card payment...
Verifying code: 67891.
现场清洁叔叔
叔叔清洁:你好,阿博·埃玛德(Mohammad的昵称),我听说您正在确保付款软件,一个好消息!
但是,如果用户开始使用信用卡会发生什么?
穆罕默德:嗨,叔叔,我知道信用卡不使用SMS验证支持2FA,因此我为此错误添加了例外。但是我认为应该以更好的方式实施。您建议我做什么?
清洁叔叔:我建议您使用接口隔离。
穆罕默德:?????
清洁叔叔:接口隔离原理(ISP)表示:客户不应被迫依靠他们不使用的接口(在您的情况下使用信用卡的SMS 2FA)。
穆罕默德:我会阅读并修复它。
使用有关ISP的不同资源阅读后,穆罕默德最终进行了此修改:
from abc import ABC, abstractmethod
class Order:
items = []
quantities = []
prices = []
status = "open"
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
class PaymentHandler(ABC):
@abstractmethod
def pay(self, order: Order):
pass
class SMSPaymentAuthHandler(PaymentHandler):
@abstractmethod
def auth_2fa_sms(self, code):
pass
class DebitPaymentHandler(SMSPaymentAuthHandler):
def __init__(self, security_code):
self.security_code = security_code
self.verified = False
def auth_2fa_sms(self, code):
print(f"Verifying 2FA using SMS code: {code}")
self.verified = True
def pay(self, order: Order):
if not self.verified:
raise Exception("Not authenticated")
print("Processing Debit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class CreditPaymentHandler(PaymentHandler):
def __init__(self, security_code):
self.security_code = security_code
def pay(self, order: Order):
print("Processing Credit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class PayPalPaymentHandler(SMSPaymentAuthHandler):
def __init__(self, email) -> None:
self.email = email
def auth_2fa_sms(self, code):
print(f"Verifying 2FA using SMS code: {code}")
self.verified = True
def pay(self, order: Order):
if not self.verified:
raise Exception("Not authenticated")
print("Processing PayPal payment...")
print(f"Verifying email: {self.email}.")
order.status = "paid"
# Making orders
order = Order()
order.add_item("Head First Object Oriented Analysis and Design Book", 1, 76)
order.add_item("Raspberry Pi Camera v2", 2, 40)
print(order.total_price())
# Payment using Debit Card
debit_payment = DebitPaymentHandler("67891")
debit_payment.auth_2fa_sms("54321")
debit_payment.pay(order)
print("#"*20)
# Payment using Credit Card
credit_payment = CreditPaymentHandler("97531")
credit_payment.pay(order)
输出:
156
Verifying 2FA using SMS code: 54321
Processing Debit Card payment...
Verifying code: 67891.
####################
Processing Credit Card payment...
Verifying code: 97531.
关于继承的组成
注意:关于继承的组成不是一个可靠的原则之一,但是在故事上下文中值得一提,因为在这种情况下它更有效。 P>
现场清洁叔叔
清洁叔叔:嗨,穆罕默德,您通过分开界面做得很好。
穆罕默德:谢谢叔叔,您的后续行动和对我的建议非常感谢。
清洁叔叔:您是否熟悉各种类型的两因素身份验证(2FA)方法?
穆罕默德:是的,我是。我知道不同类型的类型,例如基于SMS,Authenticator应用程序,基于电子邮件等等。
清洁叔叔:很高兴听到!现在,假设您遇到的情况需要将多种2FA方法用于相同的付款方式,例如将Authenticator应用程序与基于SMS的PayPal验证一起添加Authenticator App。您将如何处理?此外,您是否认为仅从2FA类继承就足以支付您的付款方式?我指的是需要将其他功能添加到您的付款课程中,而不是从2FA类继承。
穆罕默德:嗯,在某些情况下,我可以创建其他类来继承付款方式的必要功能。但是,如果我不断添加越来越多的功能,我担心长期实用性。叔叔,我想听听您对此事的想法。
清洁叔叔:在某些情况下,采用继承可能不是将特征从一个班级转移到另一个类的最实际或有效的方法。在这种情况下,建议将遗产的组成原则(COI)视为更好的替代方案。
穆罕默德:简单地说,这是什么意思?
清洁叔叔:继承的组成是OOP中的一个原则,它建议通过将较简单的组件组合而成,而不是继承,而对象从父类中继承属性和行为,从而偏爱组成或建立对象。通过组成,我们可以将较小的模块化组件结合起来,以提高灵活性和代码可重复性。它可以减少紧密的耦合,避免脆弱性并提高代码的可读性和可维护性。拥抱构图将导致更有效和适应性的代码。
穆罕默德:有趣!我会尽力应用它。谢谢叔叔。
清洁叔叔:Habibi Teslam。 (阿拉伯语中的问候语)
审查了不同的示例后,穆罕默德将其代码库更改为以下:(添加了smsauthorizer并在借记卡类中创建了一个对象
)
from abc import ABC, abstractmethod
class Order:
items = []
quantities = []
prices = []
status = "open"
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
class SMSAuthorizer:
authorized = False
def verify_code(self, code):
print(f"Verifying code {code}")
self.authorized = True
def is_authorized(self):
return self.authorized
class PaymentHandler(ABC):
@abstractmethod
def pay(self, order: Order):
pass
class DebitPaymentHandler(PaymentHandler):
def __init__(self, security_code, authorizer: SMSAuthorizer):
self.authorizer = authorizer
self.security_code = security_code
def pay(self, order: Order):
if not self.authorizer.is_authorized():
raise Exception("Not authenticated")
print("Processing Debit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class CreditPaymentHandler(PaymentHandler):
def __init__(self, security_code):
self.security_code = security_code
def pay(self, order: Order):
print("Processing Credit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class PayPalPaymentHandler(PaymentHandler):
def __init__(self, email, authorizer: SMSAuthorizer) -> None:
self.authorizer = authorizer
self.email = email
def pay(self, order: Order):
if not self.authorizer.is_authorized():
raise Exception("Not authenticated")
print("Processing PayPal payment...")
print(f"Verifying email: {self.email}.")
order.status = "paid"
# Making orders
order = Order()
order.add_item("Head First Object Oriented Analysis and Design Book", 1, 76)
order.add_item("Raspberry Pi Camera v2", 2, 40)
print(order.total_price())
# SMS Authorizer
sms_authorizer = SMSAuthorizer()
# Payment using Debit Card
debit_payment = DebitPaymentHandler("67891", sms_authorizer)
sms_authorizer.verify_code("24682")
debit_payment.pay(order)
输出:
156
Verifying code 24682
Processing Debit Card payment...
Verifying code: 67891.
5-依赖性反转原理(DIP)
此时,穆罕默德(Mohammad
现场清洁叔叔
穆罕默德:嗨,叔叔,我想知道我上周从事蘸酱。
清洁叔叔:蘸酱是什么意思?
穆罕默德:我无法想象,我正在为叔叔清洁的技术主题解释! ð
无论如何,DIP代表依赖性反转原理。原理是关于通过创建界面(例如Authorizer
)将依赖关系从高级代码中删除到低级代码。结果,高级和低级代码都取决于这些接口。
清洁叔叔:穆罕默德,很好,你很棒。基于此,您在代码中更改了什么?
Mohammad:我创建了Authorizer
,将其传递给合适的付款方式,如果它们是Authorizer
接口的子类,这使我能够传递不同的授权类型。这是以下代码:
from abc import ABC, abstractmethod
class Order:
items = []
quantities = []
prices = []
status = "open"
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
class Authorizer(ABC):
@abstractmethod
def is_authorized(self):
pass
class SMSAuthorizer(Authorizer):
authorized = False
def verify_code(self, code):
print(f"Verifying code {code}")
self.authorized = True
def is_authorized(self):
return self.authorized
class PaymentHandler(ABC):
@abstractmethod
def pay(self, order: Order):
pass
class DebitPaymentHandler(PaymentHandler):
def __init__(self, security_code, authorizer: Authorizer):
self.authorizer = authorizer
self.security_code = security_code
def pay(self, order: Order):
if not self.authorizer.is_authorized():
raise Exception("Not authenticated")
print("Processing Debit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class CreditPaymentHandler(PaymentHandler):
def __init__(self, security_code):
self.security_code = security_code
def pay(self, order: Order):
print("Processing Credit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class PayPalPaymentHandler(PaymentHandler):
def __init__(self, email, authorizer: Authorizer) -> None:
self.authorizer = authorizer
self.email = email
def pay(self, order: Order):
if not self.authorizer.is_authorized():
raise Exception("Not authenticated")
print("Processing PayPal payment...")
print(f"Verifying email: {self.email}.")
order.status = "paid"
# Making orders
order = Order()
order.add_item("Head First Object Oriented Analysis and Design Book", 1, 76)
order.add_item("Raspberry Pi Camera v2", 2, 40)
print(order.total_price())
# SMS Authorizer
sms_authorizer = SMSAuthorizer()
# Payment using Debit Card
debit_payment = DebitPaymentHandler("67891", sms_authorizer)
sms_authorizer.verify_code("24682")
debit_payment.pay(order)
叔叔干净:哇,这是一个巨大的进步。如果我们想添加recaptcha身份验证方法怎么办?依赖性反转原则在这里可以有所帮助吗?
Mohammad:当然,我将其添加到我的代码中,在该代码中,我从Authorizer
Abstract类中创建了一个具体的reCAPTCHA_Authorizer
,然后将其传递给PayPal付款类。因此,现在我可以将不同的授权和身份验证方法用于同一付款方式类。在下面查看此代码:
from abc import ABC, abstractmethod
class Order:
items = []
quantities = []
prices = []
status = "open"
def add_item(self, name, quantity, price):
self.items.append(name)
self.quantities.append(quantity)
self.prices.append(price)
def total_price(self):
total = 0
for i in range(len(self.prices)):
total += self.quantities[i] * self.prices[i]
return total
class Authorizer(ABC):
@abstractmethod
def is_authorized(self):
pass
class reCAPTCHA_Authorizer(Authorizer):
authorized = False
def verify_reCAPTCHA(self, user_selections):
print(f"Verifying reCAPTCHA {user_selections}")
print("User passed `I'm not a robot` test")
self.authorized = True
def is_authorized(self):
return self.authorized
class SMSAuthorizer(Authorizer):
authorized = False
def verify_code(self, code):
print(f"Verifying code {code}")
self.authorized = True
def is_authorized(self):
return self.authorized
class PaymentHandler(ABC):
@abstractmethod
def pay(self, order: Order):
pass
class DebitPaymentHandler(PaymentHandler):
def __init__(self, security_code, authorizer: Authorizer):
self.authorizer = authorizer
self.security_code = security_code
def pay(self, order: Order):
if not self.authorizer.is_authorized():
raise Exception("Not authenticated")
print("Processing Debit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class CreditPaymentHandler(PaymentHandler):
def __init__(self, security_code):
self.security_code = security_code
def pay(self, order: Order):
print("Processing Credit Card payment...")
print(f"Verifying code: {self.security_code}.")
order.status = "paid"
class PayPalPaymentHandler(PaymentHandler):
def __init__(self, email, authorizer: Authorizer) -> None:
self.authorizer = authorizer
self.email = email
def pay(self, order: Order):
if not self.authorizer.is_authorized():
raise Exception("Not authenticated")
print("Processing PayPal payment...")
print(f"Verifying email: {self.email}.")
order.status = "paid"
# Making orders
order = Order()
order.add_item("Domain Driven Design Book, by Eric Evans", 2, 111)
order.add_item("Raspberry Pi Pico", 3, 15)
print(order.total_price())
# reCAPTCHA Authorizer
reCAPTCHA_authorizer = reCAPTCHA_Authorizer()
# Payment using PayPal
paypal_payment = PayPalPaymentHandler("hi@customer.com", reCAPTCHA_authorizer)
reCAPTCHA_authorizer.verify_reCAPTCHA("User Selections: 1,4,7")
paypal_payment.pay(order)
输出:
267
Verifying reCAPTCHA User Selections: 1,4,7
User passed `I'm not a robot` test
Processing PayPal payment...
Verifying email: hi@customer.com.
最后的想法
首先,我要感谢故事中的角色,穆罕默德和叔叔很干净。
其次,坚实的原理旨在通过减少代码依赖性并使设计更易于理解,维护和扩展,使软件更加灵活,可维护,可扩展和测试。
但是,稳固的原则并不总是适用于每种情况,并且正确使用它们并在坚实的规则背后拥抱灵魂很重要。 ð
通过遵循这些准则,开发人员可以创建更易于修改和理解的清洁代码,从而使团队成员之间的协作更好,更健壮,灵活和可重复使用的软件。
最后,愉快的编码。
有用的链接:
GitHub version of article
Files of Code Samples
灵感来自ArjanCodes video
想要更多解释吗?询问chatgpt,bard,bing聊天和其他人。