一:设计原则
- 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化得代码混在一起。
- 针对接口编程,而非针对实现编程。
- 多用组合,少用继承。 'has a' is better than 'is a'
- 为交互对象之间的松耦合设计而努力
- 开放关闭原则:类应该对扩展开放,对修改关闭(在不修改代码的情况下,对功能进行扩展)
- 要依赖抽象,不要依赖具体类
二:策略模式(strategy)
定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
示例图:
FlyBehavior 和 QuackBehavior分别是算法族对象的接口; 客户中直接声明接口,使算法独立,不影响客户,同时使算法方法得到重用;
另一示例:comparator 和comparable
任何实现comparable接口的对象都能通过sort方法排序,同时可以通过策略模式选择每个对象的比较策略,可以为每个对象实现各自的Comparator方法。
三:观察者模式(observer)
- 定义:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会受到通知,并自动更新。
- 出版者+订阅者=观察者模式 出版者1——*订阅者
- java内置观察者模式:
观察者类 observable.class;
观察者接口Observer;
实现中subject类型的类需继承自observable.class;
observer类型的对象需实现observer接口,实现update()
四:装饰者模式(Decorator)
- 用途:在不修改任何底层代码的情况下,给你的(或别人的)对象赋予新的职责。
- 特有原则:开放-关闭原则。但在应用中让OO每个地方都采用开放-关闭原则是一种浪费,一般在设计中找到最有可能改变的地方,然后应用开放-关闭原则。
- 定义:装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
- 特性:装饰者和被装饰者有相同的超类。 可以用一个或多个装饰者逐层装饰一个对象。装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
- Whip,Mocha,DarkRoast拥有同样的超类,whip和mocha对DarkRoast进行层层装饰
五:工厂模式(Factory)
- 设计原则:要依赖抽象,不要依赖具体类。又称依赖倒置原则
- 工厂方法模式:定义了创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
- 抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定类型
- 工厂方法模式与抽象工厂对比
上例是简单工厂方法,在SimplePizzaFactory产生具体的Pizza产品。
上例是工厂模式,不同的PizzaStore根据自己店的风格生产出不同的Pizza。
上例是抽象工厂模式,每个工厂负责生产一个产品家族(我们可以设想成Pizza的产品原料)
抽象工厂负责创建一个产品家族,这个类型的子类定义了产品被产生的方法。要想使用这个工厂,必须先示例化它,然后将它传入到一些针对抽象类型所写的代码中。缺陷:当加入新产品时,需要改变接口及接口相应的子类。
六:单例模式(Singletone)
- 定义:确保一个类只有一个实例,并提供全局访问点。
-
实现:在java实现中需要私有的构造函数、一个静态方法和一个静态变量
public class Singleton { private static Singleton uniqueInstance; private Singleton(){ } public static Singleton getInstance(){ if(uniqueInstance == null){ uniqueInstance = new Singleton(); } return uniqueInstance; } }
- 用途:线程池,缓存,对话框,处理偏好设置和注册表的对象,日志对象,充当打印机、显卡等设备的驱动程序的对象
- 好处:确保一个对象只有一个实例;在需要时才创建对象(这一点解决了全局静态变量的缺点)
- 缺陷:当有多线程出现时,若同时第一次调用getInstance方法,很有可能会产生两个不同的Singleton对象,这就违反了单例原则,但若直接对getInstance对象加上synchronized则会大大降低程序的性能
- 寻求合适渠道:确保单例模式能在多线程的情况下正常工作
- 若getInstance()的性能对应用程序不是很关键,那就用synchronized做处理吧,不做其他操作。但若getInstance()频繁运行,就需要重新考虑了
- 若应用程序急切需要使用单例实例,并在创建和运行时的负担不繁重,则在声明静态变量时直接创建
- 如果很关系性能,那么用”双重检查锁“,在getInstance()中减少使用同步
public class Singleton { private volatile static Singleton uniqueInstance; private Singleton(){} public static Singleton getInstance(){ if(uniqueInstance == null){ synchronized (Singleton.class) { uniqueInstance = new Singleton(); } } return uniqueInstance; } }
只有在第一次调用getInstance()时使用同步;但不适用于 1.4及更早版本的java中
七:命令模式(Command)
- 定义:将请求封装成对象,这可以让你使用不同的请求、队列,或者日志请求来参数化其他对象。命令模式也支持撤销操作
- 实现:将发出请求的对象和执行请求的对象进行解耦;两者之间通过命令对象进行沟通
- 具体例子:设计一个遥控器API,有一个开关槽,负责管理各个电器的开关
定义Light等命令执行者,这里以Light为例
public class Light { private String name; public Light(String name) { super(); this.name = name; } public void on(){ System.out.println("light " + name +" is off"); } public void off(){ System.out.println("light " + name +" is on"); } }定义一系列命令对象,包装执行请求的对象,并定义execute()供RemoteControl进行调用,将RemoteControl和Light进行解耦。
public class LightOnCommand implements Command { Light light; public LightOnCommand(Light light){ this.light = light; } @Override public void execute() { light.on(); } }
public class LightOffCommand implements Command { Light light; public LightOffCommand(Light light){ this.light = light; } @Override public void execute() { light.off(); } }定义RemoteControl 用来管理一系列的命令对象。这里有一组是开命令对象,一组是关命令对象。
public class RemoteControl { Command[] onCommands; Command[] offCommands; /* * init the remote control : all have no command */ public RemoteControl(){ Command noCommand = new NoCommand(); onCommands = new Command[5]; offCommands = new Command[5]; for(int i=0 ;i<onCommands.length ;i++){ onCommands[i] = noCommand; offCommands[i] = noCommand; } } public void setCommand(int slot,Command onCommand,Command offCommand){ onCommands[slot] = onCommand; offCommands[slot] = offCommand; } public void onButtonWasPressed(int slot){ onCommands[slot].execute(); } public void offButtonWasPressed(int slot){ offCommands[slot].execute(); } public String toString(){ StringBuilder sb = new StringBuilder(); sb.append("\n-------Remote Control--------------\n"); for(int i = 0;i <onCommands.length;i++){ sb.append("[slot"+i+"]"+ onCommands[i].getClass().getName()+" "+offCommands[i].getClass().getName()+"\n"); } return sb.toString(); } }定义 RemoteControlLoader 来装载各个命令对象,并封装一系列的命令请求,按下按钮进行测试
public class RemoteControlLoader { public static void main(String[] args){ RemoteControl remoteControl = new RemoteControl(); Light livingRoomLight = new Light("Living Room"); Light outdoorLight = new Light("OutDoor"); GarageDoor gd = new GarageDoor(); Stereo stereo = new Stereo(); //commands Command livingRoomLightOnCommand = new LightOnCommand(livingRoomLight); Command livingRoomLightOffCommand = new LightOffCommand(livingRoomLight); Command outdoorLightOnCommand = new LightOnCommand(outdoorLight); Command outdoorlightOffCommand = new LightOffCommand(outdoorLight); Command gdOpenCommand = new GarageDoorOpenCommand(gd); Command gdCloseCommand = new GarageDoorCloseCommand(gd); Command stereoOnCommand = new StereoOnWithCDCommand(stereo); Command stereoOffCommand = new StereoOffWithCDCommand(stereo); //load the button info to remote control remoteControl.setCommand(0, livingRoomLightOnCommand, livingRoomLightOffCommand); remoteControl.setCommand(1, outdoorLightOnCommand, outdoorlightOffCommand); remoteControl.setCommand(2, gdOpenCommand, gdCloseCommand); remoteControl.setCommand(3, stereoOnCommand, stereoOffCommand); System.out.println(remoteControl);//show the remote control settings //press the button to invoke the relative commands remoteControl.onButtonWasPressed(0); remoteControl.offButtonWasPressed(0); remoteControl.onButtonWasPressed(1); remoteControl.offButtonWasPressed(1); remoteControl.onButtonWasPressed(2); remoteControl.offButtonWasPressed(2); remoteControl.onButtonWasPressed(3); remoteControl.offButtonWasPressed(3); } }
-
其他的: 若想要对一下子执行多个命令,可以创建宏命令对象
public class MacroCommand implements Command { Command[] commands; public MacroCommand(Command[] commands) { this.commands = commands; } @Override public void execute() { if(commands != null){ for(Command command : commands){ command.execute(); } } } }
在测试类中,可以创建一系列的命令对象放入宏命令对象中。 - 常见用途:日程安排,线程池,工作队列中的队列请求(工作队列类和进行计算的对象完全解耦);日志请求(将用户的操作作记录进行日志存储,一旦系统死机,这些操作记录对象将会被重新加载并以正确的次序执行)
八:适配器模式(Adapter)和外观模式(facade)
- 定义-适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本不兼容的类可以合作无间。
- 适配器模式又可分为对象适配器和类适配器
在类适配器中,需要多重继承,在java中不可能。在对象适配器中利用组合的方式将请求传送给被适配者(在Adapter中声明Adaptee实例,并调用Adaptee的方法) -
定义-外观模式:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
- 两者意图不同:适配器模式意在改变接口类型以符合客户的需求。而外观模式是提供子系统的一个简化接口,方便用户操作(类似于在一个新的接口中将子系统的一系列方法封装成另一个方法供用户使用,用户无需考虑中间都调用了哪些类;当然这些子系统的接口仍然存在供用户随时调用)
相关推荐
Java设计模式学习笔记
总结了java开发中的21种设计模式,详解和例子,带书签的pdf格式,方便阅读!
学习Java设计模式的笔记,标注了其中重要的要点,如果有需要的小伙伴,自行下载哦
java设计模式的学习笔记,其中包含各种模式的代码实现
图解java设计模式_学习笔记_java开发解压密码为twj123
Java 版设计模式学习笔记-java-design-patterns
Head First 设计模式学习笔记。更多内容请参见文章内容。
23种设计模式学习笔记及源码,全部原创 欢迎提出意见和建议
该资料介绍Java各类开发模式,包含以下教程:《深入浅出设计模式(中文版)》《Java单例模式》《Java设计模式-图解-附代码》《JAVA设计模式之单例模式(完整版)》《Java学习笔记(必看经典)》《Java总复习》《单例模式》...
设计模式学习笔记,这里面详细的记录我学习23三种设计模式的详细过程以及实例代码哦哦
该pdf是本人系统学习尚学堂推出的300Java大型设计模式部分后自己整理的学习笔记,希望对大家有帮助!!!
Java的常见集中设计模式学习笔记
定义: 结构说明: 相关概念: 接口: 接口与抽象类的区别: 面向接口编程: 功能: 时序图: 优缺点: 代码阐释:
本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式 1) 内容包括: 设计模式七大原则(单一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML...
林信良学习笔记(内容):ajax学习笔记,算法学习笔记,计算机图形学,C++学习笔记,设计模式,Hibernate学习笔记,Java学习笔记,JSF,JSP/Servlet,JUnit,Spring,Struts等
这是从网上收集而来的java学习笔记和设计模式文章,内容很经典,很值得一看。
代理模式学习笔记、单例模式学习笔记、命令模式、原型模式、模式特点总结。 为个人对设计模式的理解,如果有理解不一致的不要砸砖啊
Java设计模式,着重标注了重点,如果有需要的小伙伴,自行下载哦 目前只有7种模式,后续会增加其余的模式
尚硅谷_韩顺平_图解Java设计模式最新笔记,资料完整,学习和复习的好帮手。尚硅谷_韩顺平_图解Java设计模式最新笔记,资料完整,学习和复习的好帮手。
设计模式Head First学习笔记,以及使用java编写的设计模式源码,Java原生sdk实现23种设计模式