前言:在学习早期,你读不懂别人的代码,改不动别的代码的绝大数情况下,是因为你没有别人的架构思维,你对java设计模式一无所知
学习的书籍:HeadFirst设计模式
书籍源码可在官网下载:https://www.wickedlysmart.com/head-first-design-patterns/
github上相关的一个优秀项目:https://github.com/iluwatar/java-design-patterns
观察者模式
观察者模式类图何时适用?
- 当抽象有两个方面时,一个依赖于另一个。将这些方面封装在单独的对象中可以让您独立地改变和重用它们
- 当对一个对象的更改需要更改其他对象,而您不知道有多少对象需要更改时
- 当一个对象应该能够通知其他对象而不用假设这些对象是谁时。换句话说,你不希望这些对象紧密耦合
一个对象的变化会导致其他对象的变化
真实应用场合
-
java.util.Observer
- 缺点
- 原生Observable是一个类(JAVA不支持多继承),更有甚者,setChanged()方法是protected,意味着你必须继承自Observable。
- 缺点
- java.util.EventListener
- javax.servlet.http.HttpSessionBindingListener
- RxJava
- JavaBeans
- RMI
代码示例
public class Example {
public static void main(String[] args) {
SimpleSubject simpleSubject = new SimpleSubject();
SimpleObserver simpleObserver = new SimpleObserver(simpleSubject);
simpleSubject.setValue(80);//1.主题的数据发生了变化。
}
}
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
public interface Observer {
public void update(int value);
}
public class SimpleSubject implements Subject {
private ArrayList<Observer> observers;
private int value = 0;
public SimpleSubject() {
observers = new ArrayList<Observer>();
}
public void registerObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(i);
}
}
public void notifyObservers() {
/*3.for循环通知(实现)所有观察者进行update操作(只要你订阅了我,别想跑)*/
for (Observer observer : observers) {
observer.update(value);
}
}
//2.通知观察者
public void setValue(int value) {
this.value = value;
notifyObservers();
}
}
public class SimpleObserver implements Observer {
private int value;
private Subject simpleSubject;
public SimpleObserver(Subject simpleSubject) {
this.simpleSubject = simpleSubject;
//0.观察者首先得订阅
simpleSubject.registerObserver(this);
}
//4.更新并显示,(流程走完)。
public void update(int value) {
this.value = value;
display();
}
public void display() {
System.out.println("Value: " + value);
}
}
装饰着模式(Wrapper)
在面向对象编程中,装饰模式是一种设计模式,它允许将行为静态或动态地添加到单个对象中,而不影响同一类中其他对象的行为。装饰模式对于坚持单一责任原则通常很有用,因为它允许在具有独特关注领域的类之间划分功能。
装饰者模式类图
何时适用?
- 动态透明地向单个对象添加责任,即不影响其他对象
- 对于可以撤回的责任
- 当子类化扩展不切实际时。有时大量独立的扩展是可能的,并且会产生子类的爆炸来支持每一种组合。或者类定义可能被隐藏或者不可用于子类化
真实应用场景
- java.io.InputStream, java.io.OutputStream, java.io.Reader and java.io.Writer
- java.util.Collections#synchronizedXXX()
- java.util.Collections#unmodifiableXXX()
- java.util.Collections#checkedXXX()
代码示例
public class StarbuzzCoffee {
public static void main(String args[]) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription()
+ " $" + beverage.cost());
/*
不太懂这一块。
*/
Beverage beverage2 = new Espresso();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription()
+ " $" + beverage2.cost());
}
}
//抽象类本身不能被实例化
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
//提供一个抽象方法,子类实现。
public abstract double cost();
}
public abstract class CondimentDecorator extends Beverage {
Beverage beverage;
public abstract String getDescription();
}
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
public double cost() {
return 1.99;
}
}
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return .20 + beverage.cost();
}
}
public class Whip extends CondimentDecorator {
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public double cost() {
return .10 + beverage.cost();
}
}
工厂模式
依赖倒置原则
糟糕的情况依赖倒置原则
- 如何避免在OO设计中违反依赖倒置原则
- 变量不可以持有具体类的引用
- 不要让类派生自具体类
- 不要覆盖基类中已实现的方法
何时适用
单件模式
命令模式
命令模式将“请求”封装成对象,以便使用不用的请求、队列或者日志来参数化其他对象。命令模式也支持撤销的操作。
何时适用
- 意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
- 主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
- 何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
- 如何解决:通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。
- 关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口
- 应用实例:struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command。
- 优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
- 缺点:使用命令模式可能会导致某些系统有过多的具体命令类。
- 使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。 2、模拟 CMD。
- 注意事项:系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式,见命令模式的扩展。
真实应用场景
代码示例
public interface Command {
public void execute();
}
public class LightOnCommand implements Command {
Light light;
public LightOnCommand (Light light) {
this.light = light;
}
public void execute(){
light.on();
}
}
public class SimpleRemoteControl {
Command slot;
public SimpleRemoteControl () {};
public void setCommand(Command command){
slot = command;
}
public void buttonWasPressed(){
slot.execute( );
}
}
public class RemoteControlTest{
public static void main (String [] args){
SimpleRemoteControl remote = new SimpleRemoteControl();
Light light = new Light();
LightOnCommand lightOn = new LightOnCommand(light);
remote.setCommand(lightOn);
remote.buttonWasPressed();
}
}
网友评论