01_聊聊设计模式那点事
内容简介:干啥事情都有套路,编程序也是一样。Design Pattern就是这样一种技术,由经验丰富的程序员总结出来,把各种应用场景下的面向对象设计套路给抽象出来。类似于孙子兵法,但是任何模式都不是万能的,还是要活学活用才能事半功倍,今天就我知道的一点皮毛,来随便聊聊。

1、什么是设计模式
在你学习如何编写Python程序后,你肯定会为进入这个生态而兴奋,因为又太多的开源代码可以去使用,但是如果你遇到一个开源软件的代码,即使你懂得全部的语法仍然看不懂这些代码的含义(笔者在阅读概率编程PyMC3包的源码时就感到这种无力感),或者当你设计自己软件到一定程度时,发现代码越写越复杂,Bug越来越难以维护,软件性能提高遇到瓶颈,多人协作不起来,这时候就体现出要如何成为一个专业的软件设计者了。
而要成为专业的软件设计者,对已有设计模式的学习应该是第一门必修课。
设计模式是对设计原则的具体化。用江湖话说就是武林秘籍,总结出来的一些固定套路,可以帮助有根基的程序员迅速打通任督二脉,从此做什么都特别快。
面向对象程序设计与传统的面向过程程序设计不同,对系统设计者需要从OO角度思考如何设计,否则系统越复杂软件的维护越困难,多人协同开发也变地非常低效。
2、设计原则
通常OPP七大设计原则如下:
-
1.单一职责原则(Single Responsiblity Principle, SRP)
一个类负责一项职责。 -
2.开闭原则(Open Closed Principle, OCP)
一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。 -
3.里氏替换原则(Liskov Substitution Principle, LSP)
继承与派生的规则(子类可替换父类) -
4.依赖倒转原则(Dependency Inversion Principle, DIP)
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程。 -
5.接口隔离原则(Interface Segregation Principle, ISP)
建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。 -
6.组合/聚合复用原则(Composite/Aggregate Reuse Principle, CARP)
尽量使用组合和聚合少使用继承的关系来达到复用的原则。 -
7.最小知识原则(迪米特法则)(Principle of Least Knowledge, PLK)
高内聚,低耦合(high cohesion low coupling)。
要学好面向对象编程,需要了解设计模式。
设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码。反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。设计模式不会绑定具体的编程语言。一个好的设计模式应该能够用大部分编程语言实现(如果做不到全部的话,具体取决于语言特性)。最为重要的是,设计模式也是一把双刃剑,如果设计模式被用在不恰当的情形下将会造成灾难,进而带来无穷的麻烦。然而如果设计模式在正确的时间被用在正确地地方,它将是你的救星。
起初,你会认为“模式”就是为了解决一类特定问题而特别想出来的明智之举。说的没错,看起来的确是通过很多人一起工作,从不同的角度看待问题进而形成的一个最通用、最灵活的解决方案。也许这些问题你曾经见过或是曾经解决过,但是你的解决方案很可能没有模式这么完备。
虽然被称为“设计模式”,但是它们同“设计“领域并非紧密联系。设计模式同传统意义上的分析、设计与实现不同,事实上设计模式将一个完整的理念根植于程序中,所以它可能出现在分析阶段或是更高层的设计阶段。很有趣的是因为设计模式的具体体现是程序代码,因此可能会让你认为它不会在具体实现阶段之前出现(事实上在进入具体实现阶段之前你都没有意识到正在使用具体的设计模式)。
可以通过程序设计的基本概念来理解模式:增加一个抽象层。抽象一个事物就是隔离任何具体细节,这么做的目的是为了将那些不变的核心部分从其他细节中分离出来。当你发现你程序中的某些部分经常因为某些原因改动,而你不想让这些改动的部分引发其他部分的改动,这时候你就需要思考那些不会变动的设计方法了。这么做不仅会使代码可维护性更高,而且会让代码更易于理解,从而降低开发成本。
一般可以分为三种最基本的设计模式:
创建模式,提供实例化的方法,为适合的状况提供相应的对象创建方法。创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。为了使软件的结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。
创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。
结构化模式,通常用来处理实体之间的关系,使得这些实体能够更好地协同工作。结构型模式(Structural Pattern)描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构。
结构型模式可以分为类结构型模式和对象结构型模式:
类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。对象结构型模式关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,然后通过该对象调用其方法。根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系,因此大部分结构型模式都是对象结构型模式。
行为模式,用于在不同的实体间进行通信,为实体之间的通信提供更容易,更灵活的通信方法。
行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象之间的交互。在系统运行时,对象并不是孤立的,它们可以通过相互通信与协作完成某些复杂功能,一个对象在运行时也将影响到其他对象的运行。
行为型模式分为类行为型模式和对象行为型模式两种:
类行为型模式:类的行为型模式使用继承关系在几个类之间分配行为,类行为型模式主要通过多态等方式来分配父类与子类的职责。
对象行为型模式:对象的行为型模式则使用对象的聚合关联关系来分配行为,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责。根据“合成复用原则”,系统中要尽量使用关联关系来取代继承关系,因此大部分行为型设计模式都属于对象行为型设计模式。
第一大类:创建型(6种)
-
Factory Method(工厂方法)定义了一个创建对象的接口, 但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
-
Abstract Factory(抽象工厂)提供一个接口,用于创建相关或依赖对象的家族, 而不需要指定具体类。
-
Builder(生成器)使用生成器模式封装一个产品的构造过程, 并允许按步骤构造。将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示。
-
Prototype(原型)当创建给定类的实例过程很昂贵或很复杂时, 就使用原形模式。
-
Singleton(单例)确保一个类只有一个实例, 并提供全局访问点。
-
Multiton pattern (多例模式) 在一个解决方案中结合两个或多个模式, 以解决一般或重复发生的问题。
第二大类:结构型(7种)
-
Adapter Class/Object(适配器)将一个类的接口, 转换成客户期望的另一个接口。 适配器让原本接口不兼容的类可以合作无间. 对象适配器使用组合, 类适配器使用多重继承。
-
Bridge(桥接)使用桥接模式通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变。
-
Composite(组合)允许你将对象组合成树形结构来表现”整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
-
Decorator(装饰)动态地将责任附加到对象上, 若要扩展功能, 装饰者提供了比继承更有弹性的替代方案。
-
Facade(外观)提供了一个统一的接口, 用来访问子系统中的一群接口。外观定义了一个高层接口, 让子系统更容易使用。
-
Flyweight(享元)如想让某个类的一个实例能用来提供许多”虚拟实例”, 就使用该模式。
-
Proxy(代理)为另一个对象提供一个替身或占位符以控制对这个对象的访问.。
第三大类:行为型(11种)
-
Interpreter(解释器)使用解释器模式为语言创建解释器。
-
Template Method(模板方法)在一个方法中定义一个算法的骨架, 而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法中的某些步骤。
-
Chain of Responsibility(责任链)通过责任链模式, 你可以为某个请求创建一个对象链.。每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象。
-
Command(命令)将”请求”封闭成对象, 以便使用不同的请求,队列或者日志来参数化其他对象. 命令模式也支持可撤销的操作。
-
Iterator(迭代器)提供一种方法顺序访问一个聚合对象中的各个元素, 而又不暴露其内部的表示。
-
Mediator(中介者)使用中介者模式来集中相关对象之间复杂的沟通和控制方式。
-
Memento(备忘录)当你需要让对象返回之前的状态时(例如, 你的用户请求”撤销”), 你使用备忘录模式。
-
Observer(观察者)在对象之间定义一对多的依赖, 这样一来, 当一个对象改变状态, 依赖它的对象都会收到通知, 并自动更新。
-
State(状态)允许对象在内部状态改变时改变它的行为, 对象看起来好象改了它的类。
-
Strategy(策略)定义了算法族, 分别封闭起来, 让它们之间可以互相替换, 此模式让算法的变化独立于使用算法的客户。
-
Visitor(访问者)当你想要为一个对象的组合增加新的能力, 且封装并不重要时, 就使用访问者模式。
以上抽象的总结很难一下子理解好,设计模式都是有从事多年软件设计的专业人士从无数项目实例中总结得来,对于没有实践的初学者,只要先知道这些设计模式分类即可。