【设计模式】 装饰者与IO、Collection框架
- 格式:doc
- 大小:37.50 KB
- 文档页数:4
java最常用的六种设计模式及举例设计模式是在软件开发过程中经验总结的一种编码和设计方式,它们可以帮助我们更好地组织代码,提高代码的可维护性和可复用性。
下面是 Java 中最常用的六种设计模式及其举例:1. 单例模式:单例模式确保一个类只有一个实例,并提供一个全局访问点。
典型的例子是 `ng.Runtime` 类,在整个 JVM 中只有一个运行时实例。
2. 工厂模式:工厂模式通过一个工厂类来创建其他类的对象,将对象的创建和使用分离,降低了代码的耦合度。
比如,`java.util.Calendar` 类使用了工厂模式来创建 `Calendar` 对象,其中的 `getInstance()` 方法返回一个 `Calendar` 实例。
3. 观察者模式:观察者模式定义了对象之间的一对多的依赖关系,当一个对象状态发生改变时,其相关依赖对象会收到通知并自动更新。
一个典型的例子是使用 `java.util.Observable` 类和 `java.util.Observer`接口进行监听和通知。
4. 装饰者模式:装饰者模式通过动态地将新功能附加到对象上,为对象提供了灵活的扩展方式,不需要修改原始对象的结构。
比如,`java.io` 包中的各种装饰者类可以用来扩展输入输出功能。
5. 策略模式:策略模式定义了一组算法,并将每个算法封装到可互换的对象中,使得算法的变化不会影响到使用算法的客户端。
一个常见的例子是使用 `parator` 接口来实现不同的比较策略。
6. 适配器模式:适配器模式将一个类的接口转换成客户端所期望的另一个接口,使得原本不兼容的类可以一起工作。
比如,`java.util.Arrays` 类中的 `asList()` 方法返回的是一个适配器,可以将数组转换成 List。
通过学习这些设计模式,我们可以更好地组织和设计代码,提高代码的可读性和可维护性。
在实际的开发中,我们可以针对具体的需求选择合适的设计模式,并根据需要进行一定的修改和定制。
设计模式(三):“花瓶+鲜花”中的装饰者模式(DecoratorPattern)在前两篇博客中详细的介绍了""和“”,今天我们就通过花瓶与鲜花的例⼦来类⽐⼀下“装饰模式”(Decorator Pattern)。
在“装饰模式”中很好的提现了开放关闭原则,即类应该对扩展开放对修改关闭。
装饰者模式可以让我们在不对原来代码的修改的情况下对类进⾏扩展。
这也好⽐我们往花瓶⾥插花,我们在插花的时候是不会对花瓶以及原来的话进⾏任何的修改,⽽只管将我们新的花添加进花瓶即可。
这就是我们的装饰者模式。
当然本篇博客中所采⽤的语⾔仍然是Swift语⾔。
装饰者模式,⽤另⼀种表达⽅式就是“对原有的物体进⾏装饰,给原有的物体添加上新的装饰品”。
举个栗⼦,⽐如⼀个礼物,我们要对其进⾏包装,礼物是被装饰者(我们称为组件---Component),⽽包装盒以及包装盒上的花等等就是装饰品(我们成为装饰者---Decorator)。
如果换成花瓶与鲜花的关系,花瓶就是Component,⽽鲜花就是Decorator。
下⽅引⽤了装饰者模式的定义:装饰者模式:动态地将责任附加到对象上。
若要扩展功能,装饰着提供了⽐继承更有弹性的替代⽅案。
⼀、使⽤“类图”分析鲜花+花瓶的装饰关系与之前博客的风格类似,我们还是依托于实例来理解“装饰者模式”,我们就依托于花瓶与鲜花的关系来理解⼀下装饰者模式。
在之前的博客中我们提到过⼀条设计原则“封装变化”,也就是说要将变化的东西进⾏封装提取。
在“装饰者模式”中所使⽤的装饰就是变化的部分,也就是Decorator是变化的部分对应着我们的鲜花,因为往花瓶中插花的过程就是鲜花变化的过程,也就是为花瓶装饰的过程。
⽽花瓶就是组件了。
在“装饰者模式”中需要注意的是,这⾥所谓的装饰者不单单就是我组件添加的新的装饰品。
⼀个装饰者对象就是添加该装饰后的组件,也就是说装饰者=旧组件 + 新装饰品,理解这⼀点是⾮常重要的。
java最常用的六种设计模式及举例
1. 单例模式(Singleton Pattern):保证一个类只有一个实例,并提供一个全局访问点。
例如,数据库连接池的设计使用了单例模式。
2. 工厂模式(Factory Pattern):通过使用工厂方法来创建对象,而不是直接调用构造函数,从而实现封装和解耦的目的。
例如,Java中的Calendar类的getInstance()方法返回一个Calendar对象。
3. 观察者模式(Observer Pattern):定义对象间的一种一对多的依赖关系,当一个对象的状态改变时,所有依赖于它的对象都会自动接收到通知并更新。
例如,Java中的事件处理机制,使用了观察者模式。
4. 装饰者模式(Decorator Pattern):动态地给一个对象添加一些额外的职责,同时又不改变其结构。
例如,Java IO中的InputStream类是一个抽象类,而以其为基础的FileInputStream 类和BufferedInputStream类则是具体的装饰者。
5. 适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另外一个接口。
例如,Java中的Collections类中的方法Arrays.asList()可以将数组转换为List类型。
6. 策略模式(Strategy Pattern):封装一系列的算法,使得它们可以互相替换,而不影响使用它们的客户端。
例如,Java中
的Comparator接口和Comparable接口,用于定义排序算法的策略。
java课时培训计划第一部分:Java基础知识(20课时)1. Java语言概述(1课时)- Java语言的发展历史- Java语言的特点和应用领域2. 环境搭建与开发工具(1课时)- JDK、JRE和JVM的概念- Eclipse或IntelliJ IDEA的安装和配置3. 变量和数据类型(2课时)- 变量的声明和赋值- 基本数据类型和引用数据类型- 基本数据类型的转换4. 运算符(2课时)- 算术运算符、关系运算符、逻辑运算符- 位运算符和三目运算符5. 控制流程(3课时)- if-else语句- switch-case语句- for、while、do-while循环6. 数组(3课时)- 数组的定义和初始化- 数组的遍历和操作- 多维数组7. 方法(3课时)- 方法的定义和调用- 方法的参数传递- 方法的重载和递归8. 类和对象(3课时)- 类的定义和对象的实例化- 成员变量和成员方法- 对象的引用和赋值9. 封装和继承(2课时)- 访问权限修饰符- 继承和super关键字- 重写和重载10. 接口和抽象类(2课时)- 接口的定义和实现- 抽象类的定义和继承- 接口和抽象类的应用场景第二部分:Java进阶知识(30课时)11. 异常处理(3课时)- 异常的概念和分类- try-catch-finally结构- 自定义异常类12. 泛型(3课时)- 泛型的概念和作用- 泛型类和泛型方法- 泛型通配符和边界13. 集合框架(4课时)- Collection和Map接口- List、Set和Map的实现类- 集合的遍历和操作14. 多线程(4课时)- 线程的创建和启动- 线程的同步和通信- 线程池和线程安全15. IO流(4课时)- 输入流和输出流- 字节流和字符流- 文件的读写和操作16. 网络编程(4课时)- Socket编程- TCP和UDP协议- HTTP和Web编程17. 反射机制(3课时)- Class类的使用- 反射机制的应用场景- 动态代理和注解18. 注解(3课时)- 注解的概念和作用- 元注解和内置注解- 自定义注解和注解处理器19. 设计模式(2课时)- 单例模式、工厂模式、观察者模式 - 装饰者模式、代理模式、策略模式20. Lambda表达式和Stream API(2课时) - Lambda表达式的基本语法- Stream的创建和操作- 函数式接口和方法引用第三部分:Spring框架(40课时)21. Spring容器(3课时)- Spring的概念和特点- Bean的配置和管理- Spring容器的初始化和销毁22. Spring配置(4课时)- XML配置和注解配置- 属性注入和构造器注入- Bean的作用域和生命周期23. AOP(5课时)- AOP的概念和作用- 切面和通知的定义- AOP的实现和应用24. IOC(4课时)- 控制反转的概念和原理- Bean的依赖注入和自动装配- IOC容器的实现和应用25. Spring JDBC(4课时)- 数据库连接和事务管理- SQL语句的执行和结果集处理- 参数的绑定和存储过程调用- 事务的概念和特性- 编程式事务和声明式事务- 事务的传播行为和隔离级别27. Spring MVC(5课时)- MVC架构的概念和原理- 控制器和视图的定义- 请求映射和数据绑定28. RESTful服务(4课时)- RESTful API的概念和特点- HTTP方法和状态码- 资源的表述和链接29. Spring Boot(4课时)- Spring Boot的概念和优势- 快速入门和项目配置- 自动配置和启动器30. Spring Cloud(6课时)- 微服务架构的演变和优势- 服务注册和发现- 服务网关和负载均衡第四部分:项目实战(10课时)31. 项目需求分析(2课时)- 客户需求分析和产品定位- 系统功能和性能要求- 技术框架和开发周期- 数据库的设计范式和表结构- 数据库的关系和约束- 数据库的索引和性能优化33. 业务逻辑实现(4课时)- 业务需求的具体实现- 功能模块的开发和测试- 代码的重构和优化34. 系统集成和部署(2课时)- 系统组件的集成和测试- 系统的部署和配置- 系统的性能和稳定性测试总结与展望通过以上培训计划的学习,学员将全面掌握Java语言的基硋知识、进阶知识和主流框架的应用。
C# 设计模式之装饰者模式(Decorator Pattern)1.概述装饰者模式,英文名叫做Decorator Pattern 。
装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。
它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
2.特点(1)装饰对象和真实对象有相同的接口。
这样客户端对象就可以和真实对象相同的方式和装饰对象交互。
(2 )装饰对象包含一个真实对象的引用(reference )(3)装饰对象接受所有来自客户端的请求。
它把这些请求转发给真实的对象。
( 4 )装饰对象可以在转发这些请求以前或以后增加一些附加功能。
这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。
在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
3.应用范围1.需要扩展一个类的功能,或给一个类添加附加职责。
2.需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3.需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实4.当不能采用生成子类的方法进行扩充时。
一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
4.优点1.Decorator 模式与继承关系的目的都是要扩展对象的功能,但是Decorator 可以提供比继承更多的灵活性。
2.通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
(这一条更能体现)5.缺点1. 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
3.装饰模式是针对抽象组件 ( Component )类型编程。
但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。
当然也可以改变Component 接口,增加新的公开的行为,实现“半透明”的装饰者模式。
设计模式主要分三个类型:创建型、结构型和行为型。
创建型有:一、Singleton,单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点二、二、Abstract Factory,抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。
三、三、Factory Method,工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。
四、四、Builder,建造模式:将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示。
五、五、Prototype,原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。
行为型有:六、六、Iterator,迭代器模式:提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。
七、七、Observer,观察者模式:定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。
八、八、Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。
九、九、Command,命令模式:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。
十、十、State,状态模式:允许对象在其内部状态改变时改变他的行为。
对象看起来似乎改变了他的类。
十一、十一、Strategy,策略模式:定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。
十二、十二、China of Responsibility,职责链模式:使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系十三、十三、Mediator,中介者模式:用一个中介对象封装一些列的对象交互。
java 面向对象的常用设计模式java 面向对象的常用设计模式有:1、观察者模式观察者模式又称为发布-订阅模式,定义了对象之间一对多依赖关系,当目标对象(被观察者)的状态发生改变时,它的所有依赖者(观察者)都会收到通知。
2、抽象工厂模式抽象工厂模式主要用于创建相关对象的家族。
当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,能够保证客户端始终只使用同一个产品族中的对象;并且通过隔离具体类的生成,使得客户端不需要明确指定具体生成类;所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需要改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
3、单例设计模式单例设计模式可以确保系统中某个类只有一个实例,该类自行实例化并向整个系统提供这个实例的公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
4、策略模式将类中经常改变或者可能改变的部分提取为作为一个抽象策略接口类,然后在类中包含这个对象的实例,这样类实例在运行时就可以随意调用实现了这个接口的类的行为。
比如定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换,使得算法可独立于使用它的客户而变化,这就是策略模式。
5、适配器模式适配器模式主要用于将一个类或者接口转化成客户端希望的格式,使得原本不兼容的类可以在一起工作,将目标类和适配者类解耦;同时也符合“开闭原则”,可以在不修改原代码的基础上增加新的适配器类;将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性,但是缺点在于更换适配器的实现过程比较复杂。
6、命令模式命令模式的本质是将请求封装成对象,将发出命令与执行命令的责任分开,命令的发送者和接收者完全解耦,发送者只需知道如何发送命令,不需要关心命令是如何实现的,甚至是否执行成功都不需要理会。
命令模式的关键在于引入了抽象命令接口,发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。
装饰模式和职责链模式的对比在软件开发中,设计模式是一个十分重要的概念,是指在软件设计过程中可以重复使用的解决问题的方案。
其中,装饰模式和职责链模式都是常见的设计模式,本文将对这两种模式进行比较分析。
一、装饰模式装饰模式,是指在不改变现有对象的基础上,动态地添加一些新的功能。
这种模式通过创建一个包装对象,也可以叫做装饰器来实现。
在装饰器模式中,有三个主要角色,分别是抽象构件(Component)、具体构件(ConcreteComponent)和装饰器(Decorator)。
其中,抽象构件角色定义了抽象接口,具体构件角色实现抽象接口,而装饰器角色继承了抽象构件角色,并持有一个具体构件的实例,起到包装的作用。
装饰模式的优点是可以动态地添加或删除功能,而且可以从不同的角度来扩展一个类的功能,避免了继承带来的代码复杂性和类爆炸问题。
但缺点是装饰层数过多会增加程序的复杂度,也可能会导致增加了过多的类。
二、职责链模式职责链模式,是指通过建立一个请求的处理链,并且每个节点都有处理请求的机会,直到请求被处理完成。
这种模式拥有很强的扩展性,可以根据需要动态地改变请求的处理流程。
在职责链模式中,有两个主要角色,分别是处理者(Handler)和请求(Request)。
处理者是职责链上的节点,每个处理者都可以处理请求,如果请求不能被当前处理者处理,则将请求传递给下一级处理者。
请求则封装了请求的内容和需要执行的操作。
职责链模式的优点是将请求发送者和接收者解耦,可以动态地改变请求的处理流程,可以避免请求发送者和处理者之间的紧耦合关系。
但缺点是会导致请求的处理延迟,也需要合理设计职责链的节点顺序,避免请求被一直传递下去。
三、装饰模式和职责链模式的比较1. 功能不同装饰模式是为对象动态地添加功能,而职责链模式则是为了解耦并且动态地改变请求的处理流程。
2. 使用场景不同装饰模式适用于需要动态地添加或删除功能的场景,也适用于不想使用继承或希望从不同角度扩展类功能的场景。
【设计模式】装饰者与IO/Collection框架文章分类:Java编程装饰者模式继承是OOP程序设计的一大特点,但其实对于很多复杂问题来说,利用继承关系处理问题往往具有很高的耦合性,不利于代码的维护。
利用组合很大程度上可以做到降耦。
多用组合,少用继承是OOP设计的重要思想。
装饰者模式给我们提出了一个好的OOP设计原则:类应该对扩展开放,对修改关闭。
这句话的意思就是,如果问题发生改变,衡量一个好的设计标准就是:你不需要修改类中的代码,只需要扩展新类来适应新的行为。
《Head First Design Patterns》对装饰者模式说的很清楚。
这里稍微注意几点:(1) 装饰者和被装饰者必须具有相同的超类型。
(2) 装饰者即可以包装被装饰者,也可以包装装饰者。
往往利用多层包装来达到目的。
(3) 装饰者中组合了被装饰者对象,这是装饰类的关键特征。
正是由于这种组合,使得我们能够随心所欲的通过嵌套装饰来动态扩展行为。
Java IO框架的装饰者设计在java类库中的IO流就是用装饰者模式设计的。
JDK5.0中60多个IO流类组成了四大家族:InputStream,OutputStream,Reader,Writer。
InputStream/OutputStream是对字节序列进行操作的抽象类。
Reader/Writer是基于Unicode代码单元进行操作的抽象类。
这四大家族中大量的类都具有自己不同的功能,要做到方便的完成各种输入输出行为。
必须组合使用这些类,装饰者模式是再好不过的设计了。
那么IO类库如何实现装饰者模式的,我们看看几个类的部分源码: //InputStream:字节序列输入类鼻祖 public abstract class InputStream implements Closeable { //最基本的读取字节的抽象方法,供子类扩展。
public abstract int read() throws IOException; } //FileInputStream: 读取文件中的字节流类继承InputStream public class FileInputStream extends InputStream{ //构造器public FileInputStream(String name) throws FileNotFoundException{ //....... } //本地方法,与操作系统低层交互的具体读入方法 public native int read() throws IOException; } //FilterInputStream: 过滤流类,起装饰器作用,用于对输入装配各种功能 public class FilterInputStream extends InputStream { //用于记录被装饰者,也就是需要装配新功能的InputStream对象 protected volatile InputStream in; protectedFilterInputStream(InputStream in) { //构造装饰器 this.in = in; //设置需要被包装InputStream对象 } //读入字节 public int read() throws IOException { return in.read(); } } //BufferedInputStream: 使输入流具有缓冲功能,是一种可以装配缓冲功能的装饰器,继承FilterInputStream public class BufferedInputStream extends FilterInputStream { //构造器public BufferedInputStream(InputStream in) { this(in, defaultBufferSize); //in就是被装配缓冲功能的InputStream } }这四个类同属于InputStream家族,他们就是一个经典的装饰器模式设计。
其中InputStream 具有读入功能的抽象被装饰器。
FileInputStream 具有读入文件功能的具体被装饰器FilterInputStream 具备装饰器的抽象意义。
BufferedInputStream 具有具体功能(缓冲功能)的装饰器。
这个时候后我想设计一个具有缓冲功能的读取文件中的字节的行为:public void IOTest{ //缓冲装饰器包装文件字节输入流 BufferedInputStream bis=new BufferedInputStream(new FileInputStream("C://decorator.txt")); //读取内容 bis.read(); }IO类库中还有很多其他的装饰器,比如处理基本数据类型的DataInputStream,处理ZIP文件流的ZipInputStream,等等。
只要我们想的到的行为,都可以用这些装饰器包装组合来完成。
就这一点,装饰器绝对是Perfect。
Java Collection框架的装饰者设计在JDK类库种,集合类也使用了这种设计模式,我们看看这种设计模式给集合类库带来了什么好处?问题提出:当我们即需要List结构的可重复存储,又需要Set中高效率的查找操作。
怎么办?最好的解决办法就是:先用List存储好所有的数据,当需要查找某个元素的时候,将List对象包装成Set类型进行查找,然后返回List数据结构和Set的查找结果。
将两种不同类别的功能合并使用,装饰者模式(包装器)无疑是最好的设计。
所有实现Collection接口的集合类都有一种构造器,其参数是集合类的引用。
//ArrayList的包装构造器public ArrayList(Collection<? extends E> c) { ..... }//LinkedList的包装构造器public LinkedList(Collection<? extends E> c) { ..... }//HashSet的包装构造器 public HashSet(Collection<? extends E> c) { ..... }我们可以通过这种构造直接将一种Collection类对象包装成另一种。
//Collection类的打包过程 import java.util.*; public classTestDemo{ public static void main(String[] args){ ArrayList<String> list=new ArrayList<String>(); list.add("a1"); list.add("a1");list.add("b1"); list.add("c1"); System.out.println("List ="+list); HashSet<String> set=new HashSet<String>(list);//包装System.out.println("Set ="+set); } } /*运行结果: List =[a1, a1, b1, c1] Set =[b1, a1, c1] */值得注意的是:包装过程中集合类的存储数据类型必须兼容Collection<? extends E>。
也就是被包装集合中数据类型必须是包装集合数据类型的子类或两者类型相同。
例如:被包装的ArrayList中的数据类型是Manager,它是包装的HashSet中数据类型Employee的子类。
否则编译器不会通过。
这也是为了保证类型的自动向上转型的特性。
被包装的类型可以通过包装操作自动向上转型成父类。
//包装过程中泛型类型的兼容 import java.util.*; class Employee{ } class Manager extends Employee{ } public class TestDemo{ public static void main(String[] args){ /*error : ArrayList<Employee> list=newArrayList<Employee>(); HashSet<Manager> set=newHashSet<Manager>(list);*/ //正确: ArrayList<Manager> list=new ArrayList<Manager>(); HashSet<Employee> set=newHashSet<Employee>(list); } }顺便提一句:集合框架中的Map类型是不能和Collection类型互相包装的,他们的数据结构毕竟相差太大了。
(~你不想在商店买到的可乐里包装的是医用酒精吧)这里提一下我一直的疑问:Collection的名字有点让人费解,刚学的时候还以为他就是所有集合类的基础接口,毕竟Collection的中文意思就是集合吗? 后来发现Map类型和Collection没有一点关系,不知道Java的设计者是怎么取名字的,或者有难言之隐吧。
数组转化为集合:Array的asList()。
String[] values=".....";HashSet<String> hs=new HashSet<String>(Array.asList(values));集合转化为数组:Collection的toArray()。
HashSet<String> hs=new HashSet<String>();Object[] o=hs.toArray();千万要注意:toArray()方法返回的是一个Object[]数组。
而且你无法将其强制类型转化成你需要的数组类型。
(关于类类型间的强制类型转换,我在《【解惑】Java类型间的转型》一文中有详细阐述)String[] array=(String[])hs.toArray(); //error我们必须使用toArray的变体来做到这一点,为toArray传递一个长度为0的随意类型的数组。
然后,返回的数组就是这个类型了。
String[] array=hs.toArray(new String[0]);。