大话设计模式

16 篇文章 1 订阅

所有的设计模式都要往可复用、提升到模块的角度去想,尽量做到用最少的代码来调用。即遵循六个原则来设计。

01简单工厂模式
使用继承将原来的“过程式”的代码逻辑解耦,这样它就符合了开放—封闭原则,当需求改变时,只需要增加子类即可,而不用修改原来的类。再建立一个工厂类,工厂就是给你原料,而我不需要去考虑具体实现的细节,简单工厂类帮助我们考虑去实例化具体哪个对象。

这里写图片描述

简单工厂模式的工厂类违反了开放-封闭原则,因为当需求更改时,需要修改工厂类里的分支语句。

02策略模式(Strategy)

它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的“客户”。
这里写图片描述

定义一个接口,具体的算法都实现这个接口,在context类中,定义接口对象,定义公共方法,其方法体通过赋值的具体对象来调用接口的方法,这样可以实现的原因是多态的特性。

###06装饰模式(Decorator)
所有的类都是相似的,因为它们都依次继承下来。
调用次序,从子类开始显示,子类的show会调用父类的show,而父类的show里存放的是传过来的子类,所以会依次这么反复调用,直到最后一个子类的参数是“人”,此时就调用完了。

例子:

pqx.Decorate(xc);
kk.Decorate(pqx);
dtx.Decorate(kk);
dtx.Show();

大T恤 调用 服饰 调用 跨裤 调用 服饰 调用 破球鞋 调用 服饰 调用 人

pqx装扮的是小菜这个人,kk装扮的是已经被pqx装扮过的小菜,dtx装备的是被kk和pqx装备的小菜。可以这么调用,是因为它们都间接继承了人这个类。

小结:装饰模式,动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象值关心自己的功能,不需要关心如何被添加到对象链当中。

###07代理模式(Proxy)
声明一个接口,让真正的实现者和代理实现这个接口,这样实现者和代理中的方法都会一样了,不会少。 逻辑是这样的,实现者类中该怎么写还怎么写,代理类中定义一个实现者类,它实现接口的方法其实是调用实现者的方法,客户端调用代理。代理的功能是把真正的实现者给封装起来了。

代理模式,为其它对象提供一种代理以控制堆这个对象的访问。
####应用
第一,远程代理,也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。
第二,虚拟代理,是根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。
第三,安全代理,用来控制真实对象访问时的权限。一般用于对象应该有不同的访问权限的时候。
第四,智能指引,是指当调用真是的对象时,代理处理另外一些事。

###08工厂方法模式(Factory Method)
具有选择分支的结构,抽象出来父类,每个分支作为一个子类。定义父类,实例子类。看似是父类调用父类,实际是子类调用子类。
如果把方法都写在一个类里,那么增加功能的时候,就必须要修改类了,违反了开放—封闭原则,如果抽象成工厂,形成子类,这样增加功能就只需增加子类就可以了。

工厂方法模式,定义个一个用于创建对象的接口,让子类巨鼎实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现,选择判断的问题还是存在的,只不过工厂方法把简单工厂的内部逻辑判断移到了客户端代码中。要加功能,本来是改工厂类的,现在是修改客户端。
工厂方法模式原来的类都没有变化,而只是扩展的变化,也就是增加子类,这完全符合了开放—封闭原则。

###09原型模式(Prototype)
提供一个克隆的方法,将一个需要复制的对象赋值到一个新的对象中去,并且可以有自己可以修改的方法。需要注意的是:“浅复制”和“深复制”。
浅复制的进一层嵌套就可以形成深复制。就是说,如果被复制的类有引用类型,则在该类中需要定义一个复制这个引用类型的方法,完成一次浅复制,再定一个复制本类的方法,这个方法中需要调用前一个复制引用类型的方法,完成深复制。就是说相当于,引用类型复制两次,变成深复制。

原型模式,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
深复制与浅复制:MemberwiseClone()方法是这样,如果字段是值类型的,则对该字段执行逐位赋值;如果字段是引用类型,则赋值引用但不复制引用的对象(通俗说是复制了地址,指向同一个对象),因此,原始对象及其复本引用同一对象。

###10模板方法模式
这个就是我们最容易理解的,将重复的代码提升到模块级,提供一个虚方法来让子类重写,子类调用时,而有不同的结果。

模板方法模式,定一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
特点
模板方法模式是通过把不变的行为搬移到超类,去除子类中的重复代码来体现他的优势。就是提供了一个很好的代码复用平台。
当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重负出现。我们通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类拜托重复的不变行为的纠缠。

###12外观模式(Facade)
好像有点一对多的关系,客户端是一个,需要调用很多个相似的类时,在客户端与这些类之间增加一个类,让这个中间者里面包含了这些类。原来是客户端需要定义和调用多个类,现在是把这些工作转移到了中间类中去,这样客户端就调用中间类一个就OK了,中间类去调用很多类。

外观模式,为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
使用:
1、首先,在设计初期阶段,应该要有意识的将不同的两个层分离,比如经典的三层架构,层与层之间建立外观,这样可以为复杂的子系统提供一个简单的接口,使得耦合大大降低。
2、其次,在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,大多数的模式使用时也都会产生很多很小的类,这本是好事,但也给外部调用他们的用户程序带来了使用上的困难,增加外观Facade可以提供一个简单的接口,减少他们之间的依赖。
3、第三,在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,但因为它包含非常重要的功能,新的需求开发必须要依赖于它。你可以为新系统开发一个外观Facade类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作。

###13建造者模式(Builder)
将子类共同的部分抽象成父类,父类定义抽象接口,这样子类就不会少方法了。这里父类的作用只是起到规范的作用,子类必须实现这些方法。指导者类里有调用这些方法,传过来的参数是告诉指导者要建立哪个对象。

建造者类规范子类的方法。 指导者实现调用子类,并通过自己的一个方法将子类所有的方法包括进去,这样客户端只需调用指导者的这个方法就可以了,这个方法会去调用子类的一些方法。

建造者模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到他们,而具体建造的过程和细节就不需要知道了。

建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式。

###14观察者模式(发布—订阅模式)(Publish/Subscribe)

观察者模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
特点:
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。
当一个对象的改变需要同时改变其它对象的时候,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式
当一个抽象模型有两个方法,其中一方面依赖于另一方面,这时用观察者模式可以将者两者封装在独立的对象中使他们各自独立地改变和复用。
观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖与具体。从而使得各自的变化都不会影响到另一边的变化。

事件委托说明
委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其它任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的“类”,委托的实例将代表一个具体的函数。
一个委托可以搭载多个方法,所有方法被依次唤起。更重要的是,它可以使得委托对象所搭载的方法并不需要属于同一个类。
委托是有前提的,那就是委托对象所搭载的方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型。

###15抽象工厂模式(AbstractFactory)

抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

###16状态模式(State)
把多个状态分离开来,每个状态都是一个抽象状态的子类。其实是把状态再次抽象出来形成具有继承结构的多个类,从初始的状态开始判断,如果是就执行该状态的行为,不是就new下一个状态继续判断。本来是在一个类的很多判断转移到了一个状态类中去分别判断,判断分离。
从初始的一个状态开始判断,如果符合自己的条件就输出,如果不符合,就传给下一个状态。

状态模式,当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简单,那就没必要用“状态模式”了。
好处与用处
状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。就是将特定的状态相关的行为放入一个对象中,由于所有与状态相关的代码都存在于某个具体状态中,所以通过定义新的子类可以很容易地增加新的状态和转换。
这样做的目的就是为了消除庞大的条件分支语句,大的分支判断会使得它们难以修改和扩展。状态模式通过把各种状态逻辑转移分布到状态的子类中去,来减少相互见的依赖。
用:
当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变他的行为时,就可以考虑使用状态模式了。

###17适配器模式(Adapter)
怎么感觉有点像代理。。。就是说有两个类,它们的接口不一样,而都需要使用,就需要使用适配器模式,将它们的不同点封装起来,对外感觉变得一样了,类调用翻译,翻译调用适配类。

适配器模式,将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
系统的数据和行为都正确,但接口不符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用与希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。
两种类型:类适配器模式和对象适配器模式。
在想使用一个已经存在的类,但如果它的接口,也就是他的方法和你的要求不相同时,就应该考虑用适配器模式。两个类所做的事情相同或相似,但是具有不同的接口时要使用它。而且由于类都共享同一个接口,使得客户代码可以统一调用同意接口就行了,这样可以更简单、更直接、更紧凑。
在双方都不太容易修改的时候再使用适配器模式适配,而不是一有不同时就使用它。

###18备忘录模式(Memento)
额外定义一个类,用来保存初始的状态,此类里的字段和属性和需保存的类一模一样,不同的是它们的行为(方法)。再需要一个管理者的类,负责调用原来类里的保存状态方法,将状态传到备忘类中去。当恢复的时候,调用原来类的恢复方法备忘类作为参数传回去。

备忘录模式,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
Memento模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一小部分时,Originator(原始类)可以根据保存Memento类中的信息还原保存时的状态。
如果在某个系统中使用命令模式时,需要实现命令的撤销功能,那么命令模式可以使用备忘录模式来存储可撤销操作的状态。
使用备忘录可以把复杂的对象内部信息对其它的对象屏蔽起来,从而可以恰当地保存封装的边界。

###19组合模式(Composite)
这个模式有点像递归调用的感觉,定义根节点类和叶节子点类,根节点可以派生叶子和根,叶子节点不能派生类。根节点类中有添加根(叶)的方法。叶子类和根类完全具有一样的方法,不同的是根类有泛型属性,可以添加子类。叶子类则没有,虽然它也具有添加的方法,但它重写抽象类,让添加子类的方法什么也不做,就相当于没有这个方法。这种对象不同继承一个父类具有相同方法叫做透明方式。

组合模式,将对象组合成树形结构以表示‘部分—整体’的层次结构。组合模式使得用户对当个对象和组合对象的使用具有一致性。
当需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式了。用户不用关心到底是处理一个叶节点还是处理一个组合组件,也就用不着为定义组合而写一些选择判断语句了。组合模式让客户可以一致地使用组合结构和单个对象。

透明方式和安全方式
透明方式:
Component(抽象节点类)中声明所有用来管理子对象的方法,其中包括Add、Remove等。这样实现Component的所有子类都具备了Add和Remove。这样做的好处就是叶结点和枝节点对于外界没有区别,它们具备完全一致的行为接口。但问题也很明显,因为叶子类本身不能有Add()、Remove()方法的功能,所以它重写方法里什么都不写,实现它是没有意义的。
通俗的来说,透明方式就是“公平对待,一视同仁”;根类有的方法,叶子类也有,但有些它实现不了。
安全方式:
在Component接口(或类)中不去生命Add和Remove方法,那么子类的叶子类也就不需要去实现它,而是在Composite(根类)生命所有用来管理子类对象的方法,这样做就不会出现实现无意义的问题,但不过由于不够透明,所以树叶和树枝类将不具有相同的接口(方法),客户端调用需要做相应判断,带来了不便。

###20迭代器模式(Iterator)

迭代器模式,提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。
当需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,就应该考虑用迭代器模式。需要堆聚集有多种方式遍历时,也可以考虑用迭代器模式。
迭代器模式,为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的接口。
迭代器模式,就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。

###21单例模式(Singleton)
一个类的实例化是私有的,只能由自己new,就是它的构造函数是私有的,这样的化,外面的类就无法实例化它了。由它自己提供一个内部public方法来new,并在该方法中判断是否已经实例过了,如果实例化了就直接返回,否则new然后返回。这样就达到了只实例化一个对象的效果。

单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身复杂保存它的唯一实例。这个类可以保证没有其它实例可以被创建,并且它可以提供一个访问该实例的方法。
多线程时的单例
lock是确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其它线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
静态初始化

	public sealed class Singleton
    {
        private static readonly Singleton instance = new Singleton();
        private Singleton(){}

        public static Singleton GetInstance()
        {
            return instance;
        }
    }

这种静态初始化的方式实在自己被加载时就将自己实例化,所以被形象地称之为饿汉式单例类,原先的单例模式处理方式是要在第一次被引用时,才会将自己实例化,所以就被称为懒汉式单例类。

###22桥接模式(Bridge)
原本是一个类,但类中有些东西需要经常变化,就可以把它拆分,在抽象出来一个类,和原本的类形成聚合关系,部分与整体。部分可以单独变化而不用修改整体,整体也可以独立变化,而不用修改部分,它们都可以很好的扩展。

桥接模式,将抽象部分与它的实现部分分离,使它们都可以独立地变化。
只要真正深入地理解了设计原则,很多设计模式其实就是原则的应用而已,或许在不知不觉中就在使用设计模式了。
没看这句话之前是懂的,第一遍看完之后不懂了。第二遍在看是真正的懂了。

###23命令模式(Command)
抽象一个请求类,它可以有具体请求的子类,这样当需求发生变化,就增加子类就可以了。完美的应用了对扩展开发,对修改封闭的原则。

命令模式,讲一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
优点:
第一,它能较容易地设计一个命令队列;
第二,在需要的情况下,可以较容易地将命令记入日志;
第三,允许接收请求的一方决定是否要否决请求;
第四,可以容易地实现堆请求的撤销和重做;
第五,由于加进新的具体命令类不影响其它的类,因此增加新的具体命令类很容易。
最关键的优点就是命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分隔开。

敏捷开发原则告诉我们,不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。

###24职责链模式(Chain of Responsibility)
和状态模式感觉稍微像一点,状态模式是根据状态依次往下一个状态传而做出相应的行为,它是时刻在进行着,随着时间的进行,所有的对象都可以依次全部执行;职责链模式则是从低级向高级传递,如果低级可以执行就不会继续往上一级传,它只能执行某一个对象。

职责链模式,使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条连传递该请求,直到有一个对象处理它为止。
好处:
当客户提交一个请求时,请求是沿链传递直至有一个ConcreteHandler对象负责处理它。
接受者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构。结果是职责链可简化对象的相互连接,它仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用。

###25中介者模式(Mediator)
定义一个中介的类,它里面包含有需要通信的其它类,这些类之间的通信要通过中介来传递一次。

中介者模式,用一个中介对象来封装一系列的对象相互交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
优缺点
中介者模式很容易在系统中应用,也很容易在系统中误用。当系统出现了‘多对多’交互复杂的对象群时,不要急于使用中介者模式,而要先反思你的系统在设计上是不是合理。
由于把对象如何协作进行了抽象,将中介作为一个独立的概念并将其封装在一个对象中,这样关注的对象就从对象各自本身的行为转移到他们之间的交互上来,也就是站在一个更宏观的角度去看待系统。
由于具体中介类控制了集中化,于是就把交互复杂性变为了中介者的复杂性,这就使得中介者会变得比任何一个类都复杂。
用处
中介者模式一般应用于一组对象以定义良好但是复杂的方式进行通信的场合;以及想定制一个分布在多个类中的行为,而又不想生成太多子类的场合。

###26享元模式(Flyweight)
就是一些非常相似的内容只存储一次,而有多个引用。让一个对象被共享,多个引用指向它。

享元模式,运用共享技术有效地支持大量细粒度的对象。
可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够受大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。
如果一个应用程序使用了大量的对象, 而大量的这些对象造成了很大的存储开销时就应该考虑使用;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。

###27解释器模式(interpreter)

解释器模式,给定一个语言,定义他的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构件一个解释器,该解释器通过解决这些句子来解决该问题。
好处
当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象爱过你语法树时,可使用解释器模式。用例解释器模式,可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可使用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类易于直接编写。
不足:
解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其它的技术如语法分析程序或编译器生成器来处理。

###28访问者模式(Visitor)
对待不同的来访问的对象有不同的行为。

访问者模式,表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
访问者模式适用于数据结构相对稳定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。
它的目的是要把处理从数据结构分离出来。如果系统有比较稳定的数据结构,有又易于变化的算法的话,使用访问者模式就是比较适合的,因为访问者模式使得算法操作的增加变得容易。
访问者模式的优点就是增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。
访问者的缺点就是使增加新的数据结构变得困难了。

###还未写完。。。。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值