我正在学习GoF Java设计模式,我想看看它们的一些真实例子。 Java核心库中这些设计模式的一些很好的例子是什么?
您可以在维基百科中找到许多设计模式的概述。它还提到了GoF提到的模式。我将在这里总结它们并尝试在Java SE和Java EE API中分配尽可能多的模式实现。
创作模式
抽象工厂(可通过创建方法识别,返回工厂本身,反过来可用于创建另一个抽象/接口类型) sub>
javax.xml.parsers.DocumentBuilderFactory#newInstance()
javax.xml.transform.TransformerFactory#newInstance()
javax.xml.xpath.XPathFactory#newInstance()
Builder (可通过返回实例本身的创建方法识别) sub>
java.lang.StringBuilder#append()(未同步)
java.lang.StringBuffer#append()(已同步)
java.nio.ByteBuffer#put()(也在CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer和DoubleBuffer上)
javax.swing.GroupLayout.Group#addComponent()
java.lang.Appendable的所有实现
java.util.stream.Stream.Builder
工厂方法(可通过创建抽象/接口类型的实现的创建方法识别) sub>
java.util.Calendar#getInstance()
java.util.ResourceBundle#getBundle()
java.text.NumberFormat#getInstance()
java.nio.charset.Charset#forName()
java.net.URLStreamHandlerFactory#createURLStreamHandler(String)(每个协议返回单个对象)
java.util.EnumSet#of()
javax.xml.bind.JAXBContext#createMarshaller()和其他类似的方法
原型(可通过创建方法识别,返回具有相同属性的自身的不同实例) sub>
java.lang.Object#clone()(该类必须实现java.lang.Cloneable)
Singleton (可通过创建方法识别,每次都返回相同的实例(通常是自身)) sub>
java.lang.Runtime#getRuntime()
java.awt.Desktop#getDesktop()
java.lang.System#getSecurityManager()
结构模式
适配器(通过创建方法识别,采用不同的抽象/接口类型的实例并返回自己的实现/另一个抽象/接口类型来装饰/覆盖给定的实例) sub>
java.util.Arrays#asList()
java.util.Collections#list()
java.util.Collections#enumeration()
java.io.InputStreamReader(InputStream)(返回Reader)
java.io.OutputStreamWriter(OutputStream)(返回Writer)
javax.xml.bind.annotation.adapters.XmlAdapter#marshal()和#unmarshal()
Bridge (通过创建方法识别,采用不同的抽象/接口类型的实例并返回委托/使用给定实例的自己的抽象/接口类型的实现) sub>
没有想到的。一个虚构的例子是new LinkedHashMap(LinkedHashSet, List),它返回一个不可修改的链接映射,它不会克隆项目,而是使用它们。然而,java.util.Collections#newSetFromMap()和singletonXXX()方法非常接近。
复合(通过将相同的抽象/接口类型的实例转换为树结构的行为方法可识别) sub>
java.awt.Container#add(Component)(几乎所有的Swing因此)
javax.faces.component.UIComponent#getChildren()(几乎遍及JSF UI)
装饰器(通过创建方法识别,采用相同的抽象/接口类型的实例,增加了额外的行为) sub>
java.io.InputStream,OutputStream,Reader和Writer的所有子类都有一个构造函数,它采用相同类型的实例。
java.util.Collections,checkedXXX(),synchronizedXXX()和unmodifiableXXX()方法。
javax.servlet.http.HttpServletRequestWrapper和HttpServletResponseWrapper
javax.swing.JScrollPane
Facade (可通过内部使用不同独立抽象/接口类型的实例的行为方法识别) sub>
javax.faces.context.FacesContext,它在内部使用抽象/接口类型LifeCycle,ViewHandler,NavigationHandler等等,而不是最终用户必须担心它(但是可以通过注入覆盖)。
javax.faces.context.ExternalContext,内部使用ServletContext,HttpSession,HttpServletRequest,HttpServletResponse等。
Flyweight (通过创建方法可以识别返回缓存实例,有点"multiton"想法) sub>
java.lang.Integer#valueOf(int)(同样在Boolean,Byte,Character,Short,Long和BigDecimal)
代理(可通过创建方法识别,返回给定抽象/接口类型的实现,然后委托/使用给定抽象/接口类型的不同实现) sub>
java.lang.reflect.Proxy
java.rmi.*
javax.ejb.EJB(此处说明)
javax.inject.Inject(此处说明)
javax.persistence.PersistenceContext
行为模式
责任链(可通过行为方法识别,(间接地)在队列中的相同抽象/接口类型的另一个实现中调用相同的方法) sub>
java.util.logging.Logger#log()
javax.servlet.Filter#doFilter()
命令(可以通过抽象/接口类型中的行为方法识别,该类型调用在创建期间由命令实现封装的不同抽象/接口类型的实现中的方法) sub>
java.lang.Runnable的所有实现
javax.swing.Action的所有实现
解释器(可通过行为方法识别返回给定实例/类型的结构上不同的实例/类型;请注意,解析/格式化不是模式的一部分,确定模式以及如何应用它) sub>
java.util.Pattern
java.text.Normalizer
java.text.Format的所有子类
javax.el.ELResolver的所有子类
Iterator (通过行为方法可以从队列中顺序返回不同类型的实例来识别) sub>
java.util.Iterator的所有实现(因此也包括java.util.Scanner!)。
java.util.Enumeration的所有实现
Mediator (通过行为方法识别,采用不同的抽象/接口类型的实例(通常使用命令模式)委托/使用给定的实例) sub>
java.util.Timer(所有scheduleXXX()方法)
java.util.concurrent.Executor#execute()
java.util.concurrent.ExecutorService(invokeXXX()和submit()方法)
java.util.concurrent.ScheduledExecutorService(所有scheduleXXX()方法)
java.lang.reflect.Method#invoke()
Memento (可通过内部改变整个实例状态的行为方法识别) sub>
java.util.Date(setter方法执行此操作,Date在内部由Long值表示)
java.io.Serializable的所有实现
javax.faces.component.StateHolder的所有实现
观察者(或发布/订阅)(可通过行为方法识别,根据自己的状态调用另一个抽象/接口类型的实例上的方法) sub>
java.util.Observer / java.util.Observable(虽然在现实世界中很少使用)
java.util.EventListener的所有实现(因此几乎全部都是Swing)
javax.servlet.http.HttpSessionBindingListener
javax.servlet.http.HttpSessionAttributeListener
javax.faces.event.PhaseListener
状态(可通过行为方法识别,根据实例的状态改变其行为,可以从外部控制) sub>
javax.faces.lifecycle.LifeCycle#execute()(由FacesServlet控制,行为取决于JSF生命周期的当前阶段(状态))
策略(可通过抽象/接口类型中的行为方法识别,该类型调用不同抽象/接口类型的实现中的方法,该方法已作为方法参数传入策略实现中) sub>
java.util.Comparator#compare(),由其他Collections#sort()执行。
javax.servlet.http.HttpServlet,service()和所有doXXX()方法都需要HttpServletRequest和HttpServletResponse,并且实现者必须处理它们(而不是将它们作为实例变量保存!)。
javax.servlet.Filter#doFilter()
模板方法(可通过已经具有抽象类型定义的"默认"行为的行为方法识别) sub>
java.io.InputStream,java.io.OutputStream,java.io.Reader和java.io.Writer的所有非抽象方法。
java.util.AbstractList,java.util.AbstractSet和java.util.AbstractMap的所有非抽象方法。
javax.servlet.http.HttpServlet,默认情况下,所有doXXX()方法都会向响应发送HTTP 405"Method Not Allowed"错误。您可以自由地实施任何一个或任何一个。
访问者(可通过两种不同的抽象/接口类型识别,这些抽象/接口类型具有定义的方法,每种方法都采用其他抽象/接口类型;一个实际调用另一个的方法,另一个执行所需的策略) sub>
javax.lang.model.element.AnnotationValue和AnnotationValueVisitor
javax.lang.model.element.Element和ElementVisitor
javax.lang.model.type.TypeMirror和TypeVisitor
java.nio.file.FileVisitor和SimpleFileVisitor
javax.faces.component.visit.VisitContext和VisitCallback
好。
-
令人印象深刻.. :) +1。 javax.lang.model.element定义了访问者;)我不太确定doXXX和doFilter是否是"策略"。
-
@Bozho:谢谢你的访客榜样! (整个API对我来说实际上是新的btw)。在doXXX()和doFilter()中,您基本上只编写策略算法。服务器加载并执行它。
-
嗯,是的......我的印象是策略必须是符合策略接口的对象,因此在运行时可以互换
-
这篇相关的博客文章刚出现在briandupreez.net/2010/11/design-patterns-in-jdk.html
-
提到的建造者,例如StrinbgBuilder都不是Builder-Pattern的一个例子。然而,将它们视为构建者是一个非常常见的错误(所以你不应该责怪^ _ ^)
-
@BalusC:你确定'java.io.InputStream的所有非抽象方法,java.io.OutputStream,java.io.Reader和java.io.Writer。'是模板方法吗?例如,InputStream #available()。
-
@BalusC:Object.toString()很难被认为是工厂方法;阶级关系是正确的,但意图是错误的。当然很难画线,但任何创建和返回另一个对象的方法都不能称为工厂方法。也许你可以说toString的目的不是创建一个字符串而是关于接收者的返回信息,因此它不是工厂方法。
-
适配器示例太浅。我希望清楚地看到一个适配器接口如何支持不同的适配器接口,但是从示例中并不明显。
-
@BalusC,我有一个问题要问你。您是否阅读过Java和JSF的WHOLE源代码?
-
@Tapas:我没有阅读所有内容,只阅读了我需要的部分内容,或者只是对"他们"如何做到这一点感到好奇。
-
类似的Objective-C列表,Cocoa会很棒。
-
@rds:那是对的。你的观点是......?
-
@BalusC在Singleton设计模式中,getInstance()是返回单例的方法的名称,在我目前读过的所有书籍中(包括我所指的维基百科页面)。我发现JDK实际上没有在名为getInstance()的方法上返回单例,这让我很困惑
-
"工厂方法"下的大多数示例都是"静态工厂"的示例,它不是GoF模式。不正确。
-
docs.oracle.com/javase/tutorial/jaxp/sax/parsing.html标准SAX解析API将是访客模式的一个示例
-
什么是java.awt.GridBagConstraints?州?另外我想知道MultiValueMap是否适合桥接(但它不是Java核心)。谢谢。
-
谢谢你,但是获取每个源代码的链接会很有用(也许有人可以编辑)
-
适配器示例:java.util.Collections #enumeration(Collection c):它允许您枚举ArrayList
-
Calendar.Builder在1.8中引入,也是构建器模式的一个很好的例子。
-
@BalusC我为EnumSet的过时链接道歉。将来会对未来的编辑记住这一点。谢谢 :)
-
@BalusC InputStreamReader被记录为Oracle官方javadoc中从字节流到字符串流的桥梁。它是否有适配器?
-
@BalusC如何将序列化称为Memento?序列化本身就是愚蠢的,并没有做任何特别的事情。是序列化可以用作实现纪念品的技术之一。任何见解都会很棒。谢谢。
-
Memento vs Serialization stackoverflow.com/questions/14076772/…
-
模板示例:模板规定了算法或流程的步骤,通常涉及多个抽象方法,其实现必须由具体类填充。但我怀疑InputStream和OutputStream非抽象方法是否有资格作为模板方法
-
javax.xml.parsers.DocumentBuilderFactory不是Builder模式的一部分而不是Abstract Factory吗?
-
@Malvon:一个类可以实现多种设计模式。
-
@BalusC明白了。 JCA框架和/或Java加密怎么样?我们有任何Creational模式吗?
-
阅读投票最多的答案,发现这里提到的抽象工厂和工厂方法不是GOF书中定义的设计模式。也就是说,在谈到抽象工厂和工厂方法时,错误的答案。
-
java.util.Arrays #asList()不是JDK8状态的适配器,它接受对象并从中创建ArrayList,因此它转换不适应。
-
StringBuilder是"java builder"设计模式的一个例子,而不是GOF Builder模式。它们是不同的模式,经常混淆
-
@BalusC"请注意,解析/格式化不是模式的一部分,确定模式以及如何应用它"。关于java.util.Pattern和java.text.Format,请你详细说明一下吗?格式类必须做i)模式匹配和ii)格式化你说这个语句?如果是这样,这两个步骤之间的明显区别/边界是什么?换句话说,"格式化"步骤使用的"模式匹配"(解释)步骤的结果是什么?
-
您可以在visual-paradigm.org/category/gof-design找到GoF设计模式的可视化模型
-
我是说对org.xml.sax.ContentHandler也是访问XML元素的访问者吗?并且javax.xml.stream.XMLEventReader是迭代器...
-
这篇精彩帖子结尾处的拼写错误:"definied"。我试图改变它,但它受到像我这样的人的保护。
-
我算三:行为,创造,结构。为什么叫四人帮?编辑:以作者命名:Gamma,Erich;理查德,赫尔姆;约翰逊,拉尔夫; Vlissides,John(1995)。设计模式:可重用面向对象软件的元素。
整个摆动的观察者模式(Observable,Observer)
MVC也在摇摆
适配器模式:InputStreamReader和OutputStreamWriter
注意:ContainerAdapter,ComponentAdapter,FocusAdapter,KeyAdapter,MouseAdapter不是适配器;它们实际上是Null Objects。 Sun的命名选择不佳。
装饰器模式(BufferedInputStream可以装饰其他流,例如FilterInputStream)
AWT Toolkit和Swing可插入外观类的AbstractFactory Pattern
java.lang.Runtime#getRuntime()是Singleton
ButtonGroup for Mediator模式
Action,AbstractAction可用于不同的可视表示以执行相同的代码 - >命令模式
用于Flyweight模式的JTable中的Interned Strings或CellRender(还要考虑各种池 - 线程池,连接池,EJB对象池 - Flyweight实际上是关于共享资源的管理)
Java 1.0事件模型是责任链的一个示例,Servlet过滤器也是如此。
集合框架中的迭代器模式
AWT / Swing中的嵌套容器使用Composite模式
AWT / Swing中的布局管理器就是战略的一个例子
还有更多我猜
-
java.lang.Math(第6个)不是单例,你没有一个实例可以开始,一切都是静态的。那不是单身人士
-
感谢MouseAdapter上的提示。我发现了这个exaplanation:stackoverflow.com/questions/9244185/…
Flyweight与Byte,Short,Integer,Long和String的某些值一起使用。
Facade在很多地方使用,但最明显的是Scripting接口。
Singleton - java.lang.Runtime浮现在脑海中。
抽象工厂 - 还有脚本和JDBC API。
命令 - TextComponent的撤消/重做。
解释器 - RegEx(java.util.regex。)和SQL(java.sql。)API。
原型 - 不是100%确定是否计算,但我认为clone()方法可用于此目的。
-
关于Flyweight模式:它可能是来自java.awt和java.swing包的不同布局管理器。实际上,它们共享几乎相同的内在属性,而外在属性是它们以UI形式布局的不同UI组件。
-
@NawaMan你说5. Comand TextComponent的Undo / Redo。我认为这是memento而不是命令。或者最有可能两者。
RMI基于代理。
对于GoF中的23种模式中的大多数,应该可以引用一种:
抽象工厂:java.sql接口在注册驱动程序时从JDBC JAR获取具体实现。
Builder:java.lang.StringBuilder。
工厂方法:XML工厂等。
原型:也许克隆(),但我不确定我是买它。
Singleton:java.lang.System
适配器:java.awt.event中的适配器类,例如WindowAdapter。
Bridge:java.util中的集合类。由ArrayList实现的列表。
复合:java.awt。 java.awt.Component + java.awt.Container
装饰者:遍布java.io包。
Facade:ExternalContext表现为执行cookie,会话范围和类似操作的外观。
Flyweight:整数,字符等
代理:java.rmi包
责任链:Servlet过滤器
命令:Swing菜单项
解释器:不直接在JDK中,但JavaCC肯定使用它。
Iterator:java.util.Iterator接口;不能比那更清楚。
调解员:JMS?
纪念品:
观察者:java.util.Observer/Observable(虽然做得不好)
州:
战略:
模板:
游客:
我不能想到23个中有10个用Java的例子,但我会明白我明天能不能做得更好。这就是编辑的目的。
抽象工厂模式用于各种地方。
例如,DatagramSocketImplFactory,PreferencesFactory。还有更多---在Javadoc中搜索名称中带有"Factory"字样的接口。
此外,还有很多工厂模式的实例。
即使我有一个破坏时钟,Java XML API使用Factory很多。我的意思是看看这个:
1 2
| Document doc = DocumentBuilderFactory. newInstance(). newDocumentBuilder(). parse(source );
String title = XPathFactory. newInstance(). newXPath(). evaluate("//title", doc ); |
...等等等等。
另外,各种Buffers(StringBuffer,ByteBuffer,StringBuilder)使用Builder。
java.util.Collection #teterator是Factory方法的一个很好的例子。根据您使用的Collection的具体子类,它将创建一个Iterator实现。因为Factory超类(Collection)和Iterator都是接口,所以它有时会与AbstractFactory混淆。在接受的答案(BalusC)中,AbstractFactory的大多数示例都是Factory的示例,它是Factory Method的简化版本,它不是原始GoF模式的一部分。在Facory中,工厂类层次结构已折叠,工厂使用其他方法选择要返回的产品。
抽象工厂有多种工厂方法,每种方法都可以创建不同的产品。一家工厂生产的产品可以一起使用(您的打印机和墨盒最好来自同一个(抽象)工厂)。正如上面的答案中所提到的,不同平台的AWT GUI组件系列就是一个例子(虽然它的实现与Gof中描述的结构不同)。