zoukankan      html  css  js  c++  java
  • 设计模式

    模式是在某情境下,针对某问题的某种解决方案。

    力:问题包含了一个目标和一组约束。

    策略模式定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

    观察者模式定义了对象之间一对多依赖。当一个对象状态改变时,他的所有依赖者都会收到通知并自动更新。

    java内置观察者模式

      java.util包内包含最基本的Observer接口与Observable类。主题继承Observable类后调用setChange()方法,标记状态已改变的事实,然后调用两种notifyObservers()方法中的一个: notifyObservers()或notifyObservers(Object arg)。观察者实现Observser接口,实现了update(Observable o, Object arg),主题本身当做第一个变量,第二个变量是数据对象。

    装饰者模式动态地将责任附件到对象上。若要扩展功能,装饰者提供了比集成更有弹性的替代方案。

      装饰者和被装饰对象有相同的超类型

      可以用一个或多个装饰者包装一个对象

      既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象的场合,可以用装饰过的对象替代它

      装饰者可以在所委托被装饰者的行为之前/之后加上自己的行为,已达到特定的目的

      对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象

    工厂模式

       工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。

      abstract Product factoryMethod(String type);

    工厂方法是抽象的,所以依赖于子类来处理对象的创建;工厂方法必须返回一个产品,超类中定义的方法,通常用到工厂方法的返回值;工厂方法将客户和实际创建具体产品的代码隔离分开。

      所有工厂模式都用来封装对象的创建。工厂方法模式通过让子类决定该创建对象是什么,来达到将对象创建的过程封装的目的。

      工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

    抽象工厂模式

      提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

    单例模式

      确保一个类只有一个实例,并提供一个全局访问点。

    当多个线程同时访问这个方法的时候,可能会导致创建多个单例,此时有三种解决办法:

      1.把getInstance()变成同步synchronized方法。缺点是性能差

        public static synchronized Singleton getInstance(){...}

      2.使用急切创建实例,而不用延迟实例化的做法

        private static Singleton uniqueInstance = new Singleton();

      3.用双重检查加锁在getInstance()中减少使用同步

        private volatile static Singleton uniqueInstance;

        public static Singleton getInstance(){

          if(uniqueInstance == null){

            synchronized(Singleton.class){

              if(uniqueInstance == null){

                uniqueInstance = new Singleton();

              }

            }

          }

        }

    命令模式

      将请求封装成对象,以便使用不同的请求、队列或者日子来参数化其他对象。命令模式也支持可撤销的操作。

      命令对象将动作和接受者包进在对象中,这个对象只暴漏出一个execute()方法。

    适配器模式

      适配器模式讲一个类的接口,转换成客户希望的另一接口。适配器让原本接口不兼容的类可以合作无间

    对象适配器

      客户使用适配器的过程如下:

        客户通过目标接口调用适配器的方法对适配器发出请求

        适配器使用被适配者的接口把请求转换成被适配者的一个或多个调用接口

        客户收到调用的结果,但并未察觉到这个一切是适配器在起转换作用

    类适配器

    外观模式

      外观和适配器可以包装很多类,但是外观的意图是简化接口,而适配器的意图是将接口转换成不同的接口。

      外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

    模板方法模式

      模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。

      模板方法模式在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新第一算法中的某些步骤。

      钩子是一种被声明在抽象类中的方法,但只有空的或默认的实现。钩子的存在可以让子类有能力对算法的不同进行挂钩。要不要挂钩,由子类自行决定。

      

    迭代器模式

      提供了一种方法顺序访问一个聚合对象中的各个元素,而不是暴露其内部的表示。

      迭代器模式让我们能游走于聚合内的每一个元素,而又不暴露其内部的表示。把游走的任务放在迭代器上,而不是聚合上,这样简化了聚合的接口和实现,也让责任各得其所。

     

       空迭代器:返回null;返回一个迭代器,而这个迭代器的hasNext()永远返回false

    组合模式

      允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

      组合模式让我们能用树形方式创建对象的结构,树里面包含了组合以及个别的对象。使用组合结构,我们能把相同的操作应用在组合和个别对象上。

      组合模式以单一责任设计原则换取透明性。通过让组件的接口同时包含一些管理子节点和叶节点的操作,客户就可以将组合和叶节点一视同仁。

    状态模式

      允许对象在内部状态改变时改变它的行为,对象看起来好像修改了他的类。

      状态模式将状态封装成为独立的类,并将动作委托到代表当前状态的对象

      我们把策略模式想成是除继承外的一种弹性替代方案。把状态模式想成不用在context中设置许多条件判断的替代方案。通过将行为包装进状态对象中,可以通过在context内简单地更改状态对象来改变context的行为。

    代理模式

      远程代理就好比远程对象的本地代表。远程对象是一种对象,活在不同的Java虚拟机堆中。本地代表是一种可以由本地方法调用的对象,其行为会转发到远程对象中。你的客户对象所做的就像在做远程方法调用,但其实只是调用本地堆中“代理”对象上的方法,再由代理处理所有网络通信的底层细节。

      RMI提供了客户扶助对象和服务辅助对象,为客户辅助对象创建和服务对象相同的方法。RMI的好处在于你不必亲自写任何网络或I/O代码。客户程序调用远程方法就和运行在客户本地JVM上对对象进行正常方法调用一样。RMI也提供了所有运行时的基础设施。它查找服务(lookup service),用来寻找和访问远程对象。RMI将客户辅助对象成为stub,将服务助对象成为skeleton。

      制作远程服务的五个步骤:

        1.制作远程接口。远程接口定义出可以让客户远程调用的方法。客户将他用作服务的类类型。Stub和实际的服务都实现此接口。

          扩展java.rmi.Remote

            public interface MyRemote extends Remote

          声明所有的方法都会抛出RemoteException

            public interface MyRemote extends Remote{

              public String sayHello() throws RemoteException;

            }

          确定变量和返回值是属于原语(primitive)类型或可序列化(Serializable)类型。

            远程方法的变量必须被打包并通过网络运送,这要靠序列化来完成。如果使用原语类型、字符串和许多API内定义的类型,就不会有问题,如果需要传送自己定义的类,就必须保证你的类实现了Serialiazable。

        2.制作远程的实现。为远程接口中定义的远程方法提供真正的实现。即客户想要调用的方法的对象

          实现远程接口

            public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote(){

              public String sayHello(){

                return "Server says, hello world";

              }

           }

          实现UnicastRemoteObject

            要成为远程对象服务,你的对象需要某些“远程的”功能。最简单的方式是扩展java.rmi.server.UnicastRemoteObject,让超类帮你做这些工作。

          设计个不带变量的构造器,并声明RemoteException

            public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{

            public MyRemoteImpl() throws RemoteExcetpion{}

          }

          用RMI Registry注册此服务

            将服务实例化,然后放到RMI registry中。要先确定RMI Registry正在运行。

            try{

              MyRemote service = new MyRemoteImpl();

              Naming.rebind("RemoteHello", service);

            }catch(Excetpion e){}

        3.利用rmic产生stub和skeleton。  

          在远程实现类上执行rmic

            rmic是JDK内的一个工具,用来为一个服务类产生stub和skeleton。命名习惯是在远程实现的名字后面加上_Stub或_Skel。rmic有一些选项可以调整,包括不要产生skeleton,插卡源代码,甚至使用IIOP作为协议。

            rmit MyRemoteImpl

        4.启动RMI registry。客户可以从中查到代理的位置

          开启一个终端,启动rmiregistry。启动目录必须包含可以访问的类

          rmiregistry

        5.开启远程服务。你的服务实现类会去实例化一个服务的实例,并将这个服务注册到RMI registry。注册之后,这个服务就可以供客户调用了。

      客户获取Stub对象

        1.客户到RMI registry中寻找

          Naming.lookup("rmi://localhost/RemoteHello");

        2.RMI registry返回Stub对象

          RMI会自动对stub进行反序列化

        3.客户调用stub方法

        public class MyRemoteClient{

          public static void main(String[] args){

            new MyRemoteClient().go();

          }

          public void go(){

            try{

              MyRemote service = (MyRemote)Naming.lookup(rmi://127.0.0.1/RemoteHello);

              String s = service.sayHello();

              System.out.print(s);

            }catch(Exception e){}

          }

        }

    代理模式为另一个对象提供一个替身货占位符以控制对这个对象的访问。

      使用代理模式创建代表对象,让代表对象控制某对象的访问,被代理的对象可以是远程的对象,创建开销大的对象或需要安全控制的对象。

    远程代理可以作为另一个JVM上对象的本地代表。调用代理的方法,会被代理利用网络转发到远程执行。

    虚拟代理作为创建开销大的对象的代表。虚拟代理通常知道我们真正需要一个对象的时候才创建它。当对象在创建前和中时,由虚拟代理来扮演对象的替身,对象创建后,代理会将请求直接委托个对象。

    动态代理

    Java在java.lang.reflect包中有自己的代理支持,利用这个包可以在运行时动态地创建一个代理类,实现一个或多个接口,并将方法的调用转发到你所指定的类。

    防火墙代理:控制网络资源的访问,保护主题免于外来侵害

    智能引用代理:当主体被引用时,进行额外的动作

    缓存代理:为开销大的运算结果提供暂时存储,它也允许许多客户共享结果,以减少计算或网络延迟

    同步代理:在多线程的情况下为主题提供安全的访问

    复杂隐藏代理:用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时也撑外观代理

    写入时复制代理:用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止。

    MVC

    视图:用来呈现模型。视图通常直接从模型中取得它需要显示的状态与数据。

    控制器:取得用户的输入并解读其对模型的意思

    模型:模型持有所有的数据,状态和程序逻辑。模型没有注意到视图和控制器,虽然它提供了操纵和检索状态的接口,并发送状态改变通知给观察者

    桥接模式

    桥接模式通过将实现和抽象放在两个不同的类层次中而是他们可以独立改变。

    桥接的优点

      将实现予以解耦,让它和界面之间不再永久绑定

      抽象和实现可以独立扩展,不会影响到对方

      对于具体的抽象类所做的改变不会影响到客户

    桥接缺点:增加复杂度

    桥接用途:适合使用在需要跨越多个平台的图像和窗口的系统上;当需要用不同的方式改变接口和实现时

      

    生成器

    使用生成器模式封装一个产品的构造过程,并允许按步骤构造。

    生成器的优点

      将一个复杂对象的创建过程封装起来

      允许对象通过多个步骤来创建,并可以改变过程

      向客户隐藏产品内部的表现

      产品的实现可以被替换

    生成器的缺点:需要更多的领域知识

    生成器的用途:创建组合结构

    责任链

    当想要让一个以上的对象有机会能够处理某个请求的时候,就是用责任链模式。

    责任链的优点

      将请求的发送者和接受者解耦

      可以简化对象

      通过改变链内的成员或调动它们的次序,允许你动态地新增或删除责任

    责任链的缺点:不易观察运行时的特征,有碍于除错;并不保证请求一定被执行,若没有任何对象处理掉它的话,他可能会落到链尾端之外

    责任链的用途:经常被使用在窗口系统中

    蝇量模式

    让某个类的一个实例能用来提供许多“虚拟实例”

    优点:减少运行时对象实例的个数,节省内存;将许多虚拟对象的状态集中管理

    缺点:单个逻辑实例将无法拥有独立而不同的行为

    用途:当一个类有许多实例,而这些实例都能被同一方法控制

    解释器模式

    使用解释器模式为语言创建解释器

    解释器优点:将每个语法规则表示成一个类,方便于实现语言;因为语法由许多类表示,所以可以轻易地改变或扩展此语言;通过在类结构中加入新的方法,可以在解释的同时加入新的行为

    解释器的用途:实现一个简单的语言时;当有个简单的语法,并且简单比效率更重要;可以处理脚本语言和编译语言

    解释器缺点:当语法规则的数目太大时,这个模式可能会变得灰常繁杂。

    中介者模式

    使用中介者模式来集中相关对象之间复杂的沟通和控制方式。

    在系统中加入一个中介者,每个对象都会在自己的状态改变时,告诉中介者;每个对象都会对中介者发出的请求作出回应。

    中介者优点

      通过将对象彼此解耦,可以增加对象的复用性

      通过将控制逻辑集中,可以简化系统维护

      可以让对象之间所传递的消息变得简单而且大幅减少

    中介者缺点:如设计不当,中介者对象本身会变得过于复杂

    中介者用途:被用来协调相关的GUI组件

    备忘录

    当你需要让对象返回之前的状态模式时,就是用备忘录模式

    使用备忘录模式有两个目标;储存系统关键对象的状态;维护关键对象的封装

    备忘录优点

      将被储存的状态放在外面。不要和关键对象混在一起

      保持关键对象的数据封装

      提供了容易实现的恢复能力

    备忘录缺点:储存和恢复状态的过程很耗时

    备忘录用途:储存状态。在java中,可以使用序列化机储存系统的状态

    原型

    当创建给定类的实例的过程是很昂贵或很复杂的时候,就是用原型模式

    原型模式允许你通过复制现有的实例来创建新的实例。这个模式的重点在于,客户的代码在不知道要实例化何种特定类的情况下,可以制造出新的实例。

    原型模式的优点:

      向客户隐藏制造新实例的复杂性

      提供让客户能够产生未知类型对象的选项

      在某些环境下,复制对象比创建新对象更有效

    原型的缺点:对象的复制有时相当复杂

    原型的用途:在一个复杂的类层次中,当系统必须从其中的许多类型创建新对象时,可以考虑原型

    访问者

    当想要为一个对象的组合增加新的能力,且封装并不重要时,就是用访问者模式

    访问者必须参观组合内的每个元素;这样的功能是在导游对象中,访问者通过导游的引导,收集组合中所有对象的状态。一旦状态被收集了,客户就可以让访问者对装填进行各种操作。当需要新的功能时,只要加强访问者即可。

    访问者的优点

      允许你对组合结构加入新的操作,而无需改变结构本身

      想要加入新的操作,相对容易

      访问者所进行的操作,其代码是集中在一起的

    访问者的缺点:对组合结构的改变很困难

    访问者用途:当采用访问者模式的时候,会打破组合类的封装

    模式分类

    创建型:创建型模式涉及到对象实例化。这类模型都提供一个方法,将客户从所需要实例化的对象中解耦。Singleton,Builder,Prototype,Abstract Factory,Factory Method

    行为型:只要是行为型模式,都涉及类和对象如何交互及分配职责。Template Method, Command, Iterator,Obeserver,State,Strategy,Visitor,Mediator,Memento,Interpreter,Chain of Responsibility

    结构性:结构型模式可以让你把类或对象组合到更大的结构中。Decorator,Proxy,Composite,Facade,Adapter,Proxy,Flyweight,Bridge 

    模式按所处理的是类或对象进行分类

    类模式描述之间的关系如何通过继承定义。类模式的关系是在编译时建立的.Template Method,Factory Method,Adapter,Interpreter

    对象模式描述对象之间的关系,而且主要是利用组合定义。对象模式的关系通常在运行时建立,而且更加动态,更有弹性。Composite,Visitor,Decorator,Command,Iterator,Proxy,Facade,Mementa,Obeserver,Strategy,Chain of Responsibility,Bridge,Mediator,Flyweight,Prototype,State,Abstract Factory,Builder,Singleton

  • 相关阅读:
    我的浏览器收藏夹分类
    我的浏览器收藏夹分类
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
  • 原文地址:https://www.cnblogs.com/forerver-elf/p/5980383.html
Copyright © 2011-2022 走看看