策略模式
策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
类图:
代码:
package strategy;
public interface Strategy {
public void draw();
}
package strategy;
public class GreenPen implements Strategy{
public void draw() {
System.out.println("use green pen...");
}
}
package strategy;
public class RedPen implements Strategy {
public void draw() {
System.out.println("use red pen...");
}
}
package strategy;
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void startDraw() {
strategy.draw();
}
}
package strategy;
public class Test {
public static void main(String[] args) {
Context context = new Context(new RedPen());
context.startDraw();
}
}
运行:
观察者模式
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会收到通知并自动更新。
类图:
代码:
package observer;
public interface Observer {
public void update(int state);
}
package observer;
public class BinaryObserver implements Observer {
@SuppressWarnings("unused")
private Subject subject;
public BinaryObserver(Subject subject) {
this.subject = subject;
subject.registerObserver(this);
}
public void update(int state) {
System.out.println(Integer.toBinaryString(state));
}
}
package observer;
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
package observer;
import java.util.*;
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private int state;
public void registerObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
observers.remove(o);
}
public void notifyObservers() {
for (Observer o : observers) {
o.update(state);
}
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
}
package observer;
public class Test {
public static void main(String[] args) {
new ConcreteSubject();
new BinaryObserver(new ConcreteSubject());
ConcreteSubject subject = new ConcreteSubject();
@SuppressWarnings("unused")
Observer observer = new BinaryObserver(subject);
subject.setState(25);
}
}
运行:
装饰者模式
装饰者模式动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
类图:
代码:
package decorator;
public interface Beverage {
public void prepare();
}
package decorator;
public class Milk implements Beverage {
public void prepare() {
System.out.println("pour milk...");
}
}
package decorator;
public class Sugar implements Beverage {
private Beverage beverage;
public Sugar(Beverage beverage) {
this.beverage = beverage;
}
public void prepare() {
beverage.prepare();
System.out.println("add sugar...");
}
}
package decorator;
public class Test {
public static void main(String[] args) {
Milk milk = new Milk();
Sugar sugarMilk = new Sugar(milk);
sugarMilk.prepare();
}
}
运行:
适配器模式
适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
类图:
代码:
package adapter;
public interface Duck {
public void quack();
public void fly();
}
package adapter;
public interface Turkey {
public void gobble();
public void fly();
}
package adapter;
public class WildTurkey implements Turkey {
public void gobble() {
System.out.println("gobble,gobble...");
}
public void fly() {
System.out.println("fly a short distance...");
}
}
package adapter;
public class TurkeyAdapter implements Duck {
private Turkey turkey;
public TurkeyAdapter(Turkey turkey) {
this.turkey = turkey;
}
public void quack() {
turkey.gobble();
}
public void fly() {
for (int i = 0; i < 5; i++) {
turkey.fly();
}
}
}
package adapter;
public class Test {
public static void main(String[] args) {
Turkey turkey = new WildTurkey();
Duck duck = new TurkeyAdapter(turkey);
duck.quack();
duck.fly();
}
}
运行:
模板方法模式
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
类图:
代码:
package templatemethod;
public abstract class Beverage {
public final void prepare() {
pour();
add();
}
public final void pour() {
System.out.println("pour into cup...");
}
public abstract void add();
}
package templatemethod;
public class Coffee extends Beverage {
public void add() {
System.out.println("add sugar...");
}
}
package templatemethod;
public class Tea extends Beverage {
public void add() {
System.out.println("add lemon...");
}
}
package templatemethod;
public class Test {
public static void main(String[] args) {
Coffee coffee = new Coffee();
coffee.prepare();
Tea tea = new Tea();
tea.prepare();
}
}
运行:
命令模式
命令模式将“请求”封装成对象,将发出请求的对象和执行请求的对象解耦。
类图:
代码:
package command;
public interface Command {
public void execute();
}
package command;
public class Light {
public void on() {
System.out.println("light is on...");
}
}
package command;
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.on();
}
}
package command;
public class RemoteControl {
private Command slot;
public void setCommand(Command command) {
slot = command;
}
public void pressed() {
slot.execute();
}
}
package command;
public class Test {
public static void main(String[] args) {
Light light = new Light();
LightOnCommand lightOnCommand = new LightOnCommand(light);
RemoteControl remoteControl = new RemoteControl();
remoteControl.setCommand(lightOnCommand);
remoteControl.pressed();
}
}
运行:
外观模式
外观模式提供了一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层接口,让子系统更容易使用。
类图:
代码:
package facade;
public class Screen {
public void down() {
System.out.println("screen down...");
}
public void up() {
System.out.println("screen up...");
}
}
package facade;
public class Dvd {
public void on() {
System.out.println("turn on the dvd...");
}
public void off() {
System.out.println("turn off the dvd...");
}
}
package facade;
public class HomeTheater {
private Screen screen;
private Dvd dvd;
public HomeTheater(Screen screen, Dvd dvd) {
this.screen = screen;
this.dvd = dvd;
}
public void watch() {
screen.down();
dvd.on();
}
public void end() {
screen.up();
dvd.off();
}
}
package facade;
public class Test {
public static void main(String[] args) {
HomeTheater homeTheater = new HomeTheater(new Screen(), new Dvd());
homeTheater.watch();
homeTheater.end();
}
}
运行:
单例模式
单例模式确保一个类只有一个实例,并提供一个全局访问点。
类图:
代码:
package singleton;
//为什么要使用关键字volatile?
//防止指令重排序,对象的创建分为3步,首先分配内存,然后初始化,然后让引用指向对象的内存地址
//但是经过指令重排序之后,引用可能在初始化之前就指向内存的空间地址,这样有可能出现线程B访问到线程A未初始化的对象的情况
//使用volatile关键字防止指令重排,上述情况将不会发生
public class SingletonD {
private static volatile SingletonD uniqueInstance;
private SingletonD() {
}
public static SingletonD getInstance() {
if (uniqueInstance == null) {//位置2
synchronized (SingletonD.class) {
if (uniqueInstance == null) {
uniqueInstance = new SingletonD();//位置1
}
}
}
return uniqueInstance;
}
}
package singleton;
public class Test {
public static void main(String[] args) {
SingletonD singleton1 = SingletonD.getInstance();
SingletonD singleton2 = SingletonD.getInstance();
System.out.println(singleton1);
System.out.println(singleton2);
}
}
运行:
这里再解释一下为什么需要用关键字volatile,面试官问:为什么要使用volatile?我:为了防止指令重排序bulabula。面试官问:那如果把synchronize关键字放在整个方法上会存在这个问题吗?我:不会,synchronize关键字可以保证有序性(心虚,那之前也是用的synchronize关键字啊,只不过位置不同而已)。面试官:好了好了,问下一个吧。
我回来再想一想,如果把synchronize关键字放到整个方法上为什么不会出现问题,因为如果只对代码块加锁,当线程1执行到位置1时,有可能引用不为空,而内容(比如成员变量)为空,假设此时线程2执行到位置2,引用不为空,直接返回,那么它就拿到了一个内容为空的对象。如果对整个方法加锁,就不会出现这样的问题,即使在线程1中发生了重排序,中间结果对线程2也是不可见的。看来还是对双重检查加加锁的单例模式理解的不够透彻啊。
使用静态内部类实现单例模式:
原理,1)加载一个类时,其静态内部类不会被加载,2)虚拟机保证一个类只能被加载一次。这个方法我觉得和上一个方法相同,都是懒汉模式,都可以实现线程安全,感觉这个方法的优势就是不需要加锁和volatile。
代码:
package singleton;
public class SingletonE {
private SingletonE() {
}
public static SingletonE getInstance() {
return SingletonEHolder.UNIQUE_INSTANCE;
}
private static class SingletonEHolder {
private static final SingletonE UNIQUE_INSTANCE = new SingletonE();
}
}
package singleton;
public class Test {
public static void main(String[] args) {
SingletonE singleton1 = SingletonE.getInstance();
SingletonE singleton2 = SingletonE.getInstance();
System.out.println(singleton1);
System.out.println(singleton2);
}
}
运行:
迭代器模式
迭代器模式提供一种方法顺序访问一个聚合对象的各个元素,而又不暴露其内部的表示。
组合模式
组合模式将对象组合成树形结构来表现“整体/部分”层次结构,组合能让客户以一致的方式处理对象以及对象组合。
状态模式
状态模式在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
代理模式
代理模式为另一个对象提供一个占位符,以控制对这个对象的访问。
工厂方法模式
工厂方法模式定义了一个创建对象的接口,但由子类来决定要实例化的类是哪一个。工厂方法让类把实例化延迟到子类。
抽象工厂模式
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
注意
适配器将一个对象包装起来以改变其接口,装饰者将一个对象包装起来以增加新的行为和责任,外观将一群对象包装起来以简化其接口。
工厂方法是模板方法的一种特殊版本。
状态模式允许一个对象基于内部状态而拥有不同的行为,策略模式通常会用行为或算法来配置Context类。
代理在结构上类似装饰者,但是目的不同,装饰者为对象加上行为,而代理则是控制访问。