数个常用设计模式的简单总结与代码示例

最近读完了《Head First 设计模式》,这里对书中提到的13种设计模式做一个简单总结。文章较长,可以点击右上角图标激活目录来速查。

参考资料:


策略模式

将算法从对象中抽离出来,只提供算法接口,单独实现一族算法,根据需要动态地使用。

定义算法接口

1
2
3
public interface FlyBehavior {
void fly();
}

实现两组不同的算法

1
2
3
4
5
6
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("I'm flying!");
}
}
1
2
3
4
5
6
public class FlyRocketPowered implements FlyBehavior {
@Override
public void fly() {
System.out.println("I'm flying with a rocket!");
}
}

在对象中只保留算法接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Duck {
private FlyBehavior flyBehavior;

public Duck(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}

public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}

public void performFly() {
flyBehavior.fly();
}
}

动态选择算法(策略)

1
2
3
4
5
6
7
8
9
public class DuckSimulator {
public static void main(String[] args) {
Duck duck = new Duck(new FlyWithWings());

duck.performFly();
duck.setFlyBehavior(new FlyRocketPowered());
duck.performFly();
}
}

输出

1
2
I'm flying!
I'm flying with a rocket!

观察者模式

观察者模式定义了被观察者和观察者之间的一对多依赖,当被观察者的状态改变时,所有的观察者都能收到通知。就好像杂志出版社和订阅者之间的关系。

定义被观察者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class NewsSource extends Observable {
private String sportNews;
private String financialNews;
private String movieNews;

public void updateNews(String sportNews, String financialNews, String movieNews) {
this.sportNews = sportNews;
this.financialNews = financialNews;
this.movieNews = movieNews;

setChanged();
notifyObservers();
}

public String getSportNews() {
return sportNews;
}

public String getFinancialNews() {
return financialNews;
}

public String getMovieNews() {
return movieNews;
}
}
  • Observable类为Java内置,Java提供了对观察者模式的支持。其中包含增加/删除/通知订阅者等功能。
  • setChanged()notifyObservers()都是超类Observable的方法。
  • 每次通知观察者之前,必须调用setChanged(),因为只有在changed标志位为true的时候才会真正通知观察者。调用完后无需手动设回false,这个操作会自动完成。
  • Observable是个类,而非接口。

定义多个观察者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SportNewsReporter implements Observer {
private Observable newsSource;

public SportNewsReporter(Observable newsSource) {
this.newsSource = newsSource;
newsSource.addObserver(this);
}

@Override
public void update(Observable observable, Object arg) {
if (observable instanceof NewsSource) {
System.out.println("Sport News: " + ((NewsSource) observable).getSportNews());
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FinancialNewsReporter implements Observer {
private Observable newsSource;

public FinancialNewsReporter(Observable newsSource) {
this.newsSource = newsSource;
newsSource.addObserver(this);
}

@Override
public void update(Observable observable, Object arg) {
if (observable instanceof NewsSource) {
System.out.println("Financial News: " + ((NewsSource) observable).getFinancialNews());
}
}
}
  • Observer接口为Java自带。注意这里是接口,而被观察者用的是
  • 每个观察者都保存了一个被观察者,并在初始化时传入。就好像每个订阅者都知道自己所订阅的出版社。
  • update方法是Observer接口里的,被观察者调用此方法时可以将自己传入,然后观察者便可以访问到被观察者的状态。

通知观察者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {
public static void main(String[] args) {
NewsSource newsSource = new NewsSource();

Observer financialNewsReporter = new FinancialNewsReporter(newsSource);
Observer sportNewsReporter = new SportNewsReporter(newsSource);

String sportNews = "This is sport news!";
String financialNews = "This is financial news!";
String movieNews = "This is movie news!";

newsSource.updateNews(sportNews, financialNews, movieNews);
}
}
  • updateNews()里,我们调用了notifyObservers()。这个方法是Observable里的,它会遍历自己的观察者列表,并调用每个观察者的update()方法,而观察者的update()方法在实现Observer时已经被重写,因此可以实现不同的效果。
  • 无需显示调用观察者的方法,理由如上所述,在被观察者更新时它们会被自动调用。

输出

1
2
Sport News: This is sport news!
Financial News: This is financial news!

装饰器模式

装饰器与被装饰的对象类型相同(通过让两者实现同一个接口或是继承同一个类来实现),并在装饰器里包含一个被装饰的对象实例。这样,便可以通过调用装饰器里的同名方法来调用被装饰对象对应的方法,并在之前或之后做一些额外的操作,以此来扩展被装饰对象的功能。

调用同名方法和代理很相似,但是这里是把被装饰对象组合进装饰器里,实现或继承自同一个接口仅仅只是为了能让装饰器和被装饰者有同样的类型,方便使用多态。

优点:

  • 可以在运行时动态扩展对象的功能。
  • 相比静态的继承更为灵活,不用为每一个功能增加大量子类。
  • 与被装饰类解耦,可替代继承。

组件

定义组件接口

1
2
3
public interface Shape {
void draw();
}

实现组件

1
2
3
4
5
6
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}
1
2
3
4
5
6
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}

目前为止,写出的代码都和装饰器模式没有关系。假设现在想要想增加一种红色的图形和一种蓝色的图形,如果使用继承的话,会新增以下子类:

  • RedCircle
  • RedRectangle
  • BlueCircle
  • BlueRectangle

4个子类尚可接受,但如果要再增加十种颜色和二十种图形,需要创建的子类就成了200个。

装饰器

定义装饰器抽象类

1
2
public abstract class ShapeDecorator implements Shape {
}

实现装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
public class RedShapeDecorator extends ShapeDecorator {
private Shape decoratedShape;

public RedShapeDecorator(Shape decoratedShape) {
this.decoratedShape = decoratedShape;
}

@Override
public void draw() {
System.out.print("[Red Border]");
decoratedShape.draw();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class BlueShapeDecorator extends ShapeDecorator {
private Shape decoratedShape;

public BlueShapeDecorator(Shape decoratedShape) {
this.decoratedShape = decoratedShape;
}

@Override
public void draw() {
System.out.print("[Blue Border]");
decoratedShape.draw();
}
}
  • 这里的抽象类没有做任何事,因此也可以让两个装饰器的实现类直接实现Shape。这么写是为了更通用,因为除了实现组件接口外有可能使用继承,这时候就需要显式的写出要重写的方法。
  • 装饰器包含一个被装饰对象。
  • 在调用被装饰对象的方法之前或者之后,做一些额外的操作来实现功能的扩展。

运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class App {
public static void main(String[] args) {
Shape circle = new Circle();
circle.draw();
circle = new RedShapeDecorator(circle);
circle.draw();

Shape rectangle = new Rectangle();
rectangle.draw();
rectangle = new RedShapeDecorator(rectangle);
rectangle = new BlueShapeDecorator(rectangle);
rectangle.draw();
}
}

输出

1
2
3
4
Shape: Circle
[Red Border]Shape: Circle
Shape: Rectangle
[Blue Border][Red Border]Shape: Rectangle

工厂模式

工厂模式细分为三种:

  • 简单工厂。将对象的创建逻辑放到单独一个类中。
  • 工厂方法。将基类定义为抽象类,并把创建对象的代码单独抽出来作为一个抽象方法。具体的创建逻辑通过子类覆盖这个方法来实现。适合所需创建的对象种类较少时使用。
  • 抽象工厂。创建一个接口或者抽象类,里面包含创建各种对象的方法定义,通过实现/继承这个接口/抽象类来实现不同的创建逻辑,最后再将这个实现引入别的类中。适合所需创建的对象种类较多时使用。

简单工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class PizzaStore {
private SimplePizzaFactory simplePizzaFactory;

public PizzaStore(SimplePizzaFactory simplePizzaFactory) {
this.simplePizzaFactory = simplePizzaFactory;
}

public Pizza orderPizza(String type) {
Pizza pizza;

pizza = simplePizzaFactory.createPizza(type);
pizza.box();

return pizza;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SimplePizzaFactory {
public Pizza createPizza(String type) {
Pizza pizza = null;

if ("cheese".equals(type)) {
pizza = new CheesePizza();
} else if ("fruit".equals(type)) {
pizza = new FruitPizza();
} else if ("claim".equals(type)) {
pizza = new ClaimPizza();
}

return pizza;
}
}

这里的工厂类是一个普通的类。

优点:

  • 实例化逻辑与业务逻辑解耦

工厂方法

1
2
3
4
5
6
7
8
9
10
11
12
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza;

pizza = createPizza(type);
pizza.box();

return pizza;
}

abstract Pizza createPizza(String type);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class NYStylePizzaStore extends PizzaStore {
@Override
Pizza createPizza(String type) {
Pizza pizza = null;

if ("cheese".equals(type)) {
pizza = new NYCheesePizza();
} else if ("fruit".equals(type)) {
pizza = new NYFruitPizza();
} else if ("claim".equals(type)) {
pizza = new NYClaimPizza();
}

return pizza;
}
}

这里的基类是抽象类,因为工厂方法是抽象的。工厂方法在子类里被实现。

优点:

  • 与简单工厂相比,提供了更多的灵活性。可以根据不同的需求创建不同的子类,以此实现多种创建逻辑并存。

抽象工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PizzaStore {
private PizzaFactory pizzaFactory;

public PizzaStore(PizzaFactory pizzaFactory) {
this.pizzaFactory = pizzaFactory;
}

public Pizza orderPizza(String type) {
Pizza pizza;
Box box;

pizza = pizzaFactory.createPizza(type);
box = pizzaFactory.createBox();
pizza.setBox(box);

return pizza;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class NYPizzaFactory implements PizzaFactory {
@Override
public Pizza createPizza(String type) {
Pizza pizza = null;

if ("cheese".equals(type)) {
pizza = new NYCheesePizza();
} else if ("fruit".equals(type)) {
pizza = new NYFruitPizza();
} else if ("claim".equals(type)) {
pizza = new NYClaimPizza();
}

return pizza;
}

@Override
public Box createBox() {
return new Box("NY");
}
}

这里的工厂类是接口,根据需求来实现这个接口。抽象工厂简单工厂很像,只不后者使用的是普通类,而前者将其抽象化,使其变成接口或者抽象类,从而提供了更良好的扩展性。

优点:

  • 与工厂方法相比,可以在一个工厂里包含多种对象的创建逻辑。
  • 扩展性好,可以根据不同需求实现接口来提供不同的创建逻辑。
  • 使用的是组合而不是继承。

单例模式

与人工保证全局只实例化一个对象不同,单例模式通过代码层级来确保某个类只会被实例化一次。有几种比较常用的方法来实现单例模式。

  • synchronized
  • 双重检查锁
  • 静态初始化
  • 静态内部类
  • 枚举

synchronized

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton {
private static Singleton uniqueInstance;

private Singleton() {
}

public static synchronized Singleton getInstance() {
if (null == uniqueInstance) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}

优点:

  • 私有构造函数确保其不能在外部被实例化。
  • synchronized关键字确保了多线程的时候不会创建出多个实例。

缺点:

  • 每一次调用时都会同步,造成了很大的性能开销。实际上只需第一次调用时进行同步就可以了。

双重检查锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Singleton {
private volatile static Singleton uniqueInstance;

private Singleton() {
}


public static Singleton getInstance() {
if (null == uniqueInstance) {
synchronized (Singleton.class) {
if (null == uniqueInstance) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}

优点:

  • 私有构造函数确保其不能在外部被实例化。
  • 双重空检查导致只有第一次调用时进行同步,因此只有第一次才会有性能花销。

缺点:

  • 相比上一种写法略微复杂。

静态初始化

1
2
3
4
5
6
7
8
9
10
public class Singleton {
private static Singleton uniqueInstance = new Singleton();

private Singleton() {
}

public static Singleton getInstance() {
return uniqueInstance;
}
}

优点:

  • 私有构造函数确保其不能在外部被实例化。
  • 静态初始化确保只会被初始化一次。
  • 无同步带来的性能开销。

缺点:

  • 在程序开始运行时就会创建实例,可能导致无必要的花销。

静态内部类

1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton {
private static class SingletonHolder {
private static final Singleton UNIQUE_INSTANCE = new Singleton();
}

private Singleton() {
}

public static Singleton getInstance() {
return SingletonHolder.UNIQUE_INSTANCE;
}
}

优点:

  • 继承了静态初始化方法的所有优点,并且实现了懒加载。

缺点:

  • 相对上一种写法略复杂。

枚举

1
2
3
4
5
6
public enum Singleton {
INSTANCE;

public void someMethod() {
}
}

优点:

  • 实现非常简洁

缺点:

  • JDK 1.5之前的版本不支持

命令模式

命令模式将“请求”封装成对象,将发出请求的对象与执行请求的对象之间解耦,请求发出者无需关心请求是怎样实现的。命令模式和策略模式有点相似,但是命令模式是调用同一个接口做毫无相关的事,而策略模式是调用同一个接口做相似的事。

命令接口

1
2
3
4
public interface Command {
void execute();
void undo();
}

命令请求者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Remote {
private Command[][] commands;
private Command undoCommand;

public Remote() {
commands = new Command[7][];
for (int i = 0; i < 7; i++) {
commands[i] = new Command[2];
commands[i][0] = new NoCommand();
commands[i][1] = new NoCommand();
}
undoCommand = new NoCommand();
}

public void setCommand(int slide, Command onCommand, Command offCommand) {
commands[slide][0] = onCommand;
commands[slide][1] = offCommand;
}

public void onButtonWasPushed(int slide) {
commands[slide][0].execute();
undoCommand = commands[slide][0];
}

public void offButtonWasPushed(int slide) {
commands[slide][1].execute();
undoCommand = commands[slide][1];
}

public void undoButtonWasPushed() {
undoCommand.undo();
}
}

假设有一个遥控器,遥控器上有很多排按键,每一排都有一个“开”按键和一个“关”按键,同时还有一个全局的“撤销”键。

这里遥控器对于每一个按键具体控制什么并不关心,只需要它是一个Command接口就可以了,这样遥控器就可以调用它的execute()undo()功能。

命令执行者

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Light {
private boolean on;

public void on() {
System.out.println("Light On");
on = true;
}

public void off() {
System.out.println("Light Off");
on = false;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class LightOnCommand implements Command {
private Light light;

public LightOnCommand(Light light) {
this.light = light;
}

@Override
public void execute() {
light.on();
}

@Override
public void undo() {
light.off();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class LightOffCommand implements Command {
private Light light;

public LightOffCommand(Light light) {
this.light = light;
}

@Override
public void execute() {
light.off();
}

@Override
public void undo() {
light.on();
}
}

设置命令并执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class App {
public static void main(String[] args) {
Remote remote = new Remote();

Command lightOnCommand = new LightOnCommand(new Light());
Command lightOffCommand = new LightOffCommand(new Light());

remote.setCommand(0, lightOnCommand, lightOffCommand);

remote.onButtonWasPushed(0);
remote.offButtonWasPushed(0);

remote.undoButtonWasPushed();

}
}

输出

1
2
3
Light On
Light Off
Light On

适配器模式

适配器模式将一个类的接口转换成另一个接口,使得原本不兼容的类可以当成同一个类来使用。

两组不同的接口

1
2
3
4
public interface Duck {
void quack();
void fly();
}
1
2
3
4
public interface Turkey {
void gobble();
void fly();
}

两组实现

1
2
3
4
5
6
7
8
9
10
11
public class MallardDuck implements Duck {
@Override
public void quack() {
System.out.println("Quack");
}

@Override
public void fly() {
System.out.println("I'm flying");
}
}
1
2
3
4
5
6
7
8
9
10
11
public class WildTurkey implements Turkey {
@Override
public void gobble() {
System.out.println("Gobble gobble");
}

@Override
public void fly() {
System.out.println("I'm flying a short distance");
}
}

适配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TurkeyAdapter implements Duck {
private Turkey turkey;

public TurkeyAdapter(Turkey turkey) {
this.turkey = turkey;
}

@Override
public void quack() {
turkey.gobble();
}

@Override
public void fly() {
turkey.fly();
}
}

现在假设想将火鸡当成鸭子来调用,这时候就需要创建一个适配器,将火鸡适配到鸭子。

1
2
3
4
5
6
7
8
public class App {
public static void main(String[] args) {
Duck turkeyAdapter = new TurkeyAdapter(new WildTurkey());

turkeyAdapter.quack();
turkeyAdapter.fly();
}
}

现在,就可以调用把这个适配器当成鸭子来调用。


外观模式

外观模式提供了一个接口简化的类,用来包装系统中一系列复杂的调用。使用外观模式可以隐藏系统的复杂性,避免和客户和子系统之间的耦合。

外观类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ShapeFacade {
private Shape circle;
private Shape rectangle;
private Shape square;

public ShapeMaker() {
circle = new Circle();
rectangle = new Rectangle();
square = new Square();
}

public void drawShape(){
circle.draw();
rectangle.draw();
square.draw();
}
}

可以看到,外观类将一系列复杂的调用集成进一个简单的接口,屏蔽了复杂的调用细节。

调用

1
2
3
4
5
6
7
public class FacadePatternDemo {
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();

shapeMaker.drawShape();
}
}

模板模式

模板模式定义了一个算法的大纲,并允许子类为一个或者多个大纲里的步骤提供实现。

定义模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public abstract class Game {

//模板
public final void play() {

//初始化游戏
initialize();

//开始游戏
startPlay();

//计分
if (wantScore()) {
makeScore();
}

//结束游戏
endPlay();
}

void endPlay() {
System.out.println("Good Game!");
}

//钩子
boolean wantScore() {
return true;
}

abstract void initialize();

abstract void startPlay();

abstract void makeScore();
}
  • 算法大纲被定义为final,以防被子类修改。
  • 具体步骤被定义成abstract,让子类提供具体实现。
  • 一些重复的步骤被直接实现,比如endPlay()
  • 钩子是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子的存在使得子类有能力选择要不要某些算法。

迭代器模式

迭代器模式提供了一种方法来顺序访问一个集合对象中的各个元素,而又不用知道集合内部是怎么表示的。

定义迭代器接口

1
2
3
4
public interface Iterator {
Object next();
boolean hasNext();
}

实现迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class NameIterator implements Iterator {
private int position;
private String[] names;

public NameIterator(String[] names) {
this.names = names;
}

@Override
public Object next() {
String name = names[position];
position++;
return name;
}

@Override
public boolean hasNext() {
return position < names.length;
}
}

从集合中获取迭代器

1
2
3
4
5
6
7
8
9
10
11
public class NameCollection {
private String[] names = new String[]{"Tom", "Jane", "Bob"};

public String[] getNames() {
return names;
}

public Iterator createIterator() {
return new NameIterator(names);
}
}

使用迭代器

1
2
3
4
5
6
7
8
9
10
public class App {
public static void main(String[] args) {
NameCollection nameCollection = new NameCollection();
Iterator iterator = nameCollection.createIterator();

while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
  • 使用了迭代器模式后,只需简单的获取迭代器并调用hasNext()next()方法,就可以完成集合元素的遍历,而无需关心集合内部是用什么数据结构储存元素的。

组合模式

组合模式允许将对象组合成树形结构,即一个对象中包含其他对象,被包含的对象可能是叶子节点,也有可能是非叶子节点(其内部还包含其他对象)。组合模式使得客户能以一致的方式处理叶子对象和非叶子对象。

定义节点结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Employee {
private String name;
private String department;
private int salary;
private List<Employee> subordinates;

public Employee(String name, String department, int sal) {
this.name = name;
this.department = department;
this.salary = sal;
subordinates = new ArrayList<Employee>();
}

public void add(Employee e) {
subordinates.add(e);
}

public void remove(Employee e) {
subordinates.remove(e);
}

public List<Employee> getSubordinates() {
return subordinates;
}

// 递归处理
public void display() {
System.out.println(this);
for (Employee employee : subordinates) {
employee.display();
}
}

@Override
public String toString() {
return ("Employee :[ Name : " + name
+ ", department : " + department + ", salary :"
+ salary + " ]");
}
}

因为采用了组合模式,所以可以用同样的代码来打印出员工信息,无论员工是否下面还有下级。

构建树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class App {
public static void main(String[] args) {
Employee CEO = new Employee("John", "CEO", 30000);

Employee headSales = new Employee("Robert", "Head Sales", 20000);

Employee headMarketing = new Employee("Michel", "Head Marketing", 20000);

Employee clerk1 = new Employee("Laura", "Marketing", 10000);
Employee clerk2 = new Employee("Bob", "Marketing", 10000);

Employee salesExecutive1 = new Employee("Richard", "Sales", 10000);
Employee salesExecutive2 = new Employee("Rob", "Sales", 10000);

CEO.add(headSales);
CEO.add(headMarketing);

headSales.add(salesExecutive1);
headSales.add(salesExecutive2);

headMarketing.add(clerk1);
headMarketing.add(clerk2);

CEO.display();
}
}

输出

1
2
3
4
5
6
7
Employee :[ Name : John, department : CEO, salary :30000 ]
Employee :[ Name : Robert, department : Head Sales, salary :20000 ]
Employee :[ Name : Richard, department : Sales, salary :10000 ]
Employee :[ Name : Rob, department : Sales, salary :10000 ]
Employee :[ Name : Michel, department : Head Marketing, salary :20000 ]
Employee :[ Name : Laura, department : Marketing, salary :10000 ]
Employee :[ Name : Bob, department : Marketing, salary :10000 ]

状态模式

状态模式允许对象在内部状态改变时改变它调用同样方法的行为,使得对象看来好像修改了它的类。代码中包含大量与对象状态有关的条件语句时可以考虑使用此模式。

定义状态接口

1
2
3
4
public interface State {
void start();
void stop();
}

实现一系列状态

1
2
3
4
5
6
7
8
9
10
11
public class StartState implements State {
@Override
public void start() {
System.out.println("App Already Started!");
}

@Override
public void stop() {
System.out.println("App Stopped!");
}
}
1
2
3
4
5
6
7
8
9
10
11
public class StopState implements State {
@Override
public void start() {
System.out.println("App Started!");
}

@Override
public void stop() {
System.out.println("App Already Stopped!");
}
}

使用状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class App {
private State startState = new StartState();
private State stopState = new StopState();
private State state = stopState;

public void startApp() {
state.start();
this.state = startState;
}

public void stopApp() {
state.stop();
this.state = stopState;
}

public static void main(String[] args) {
App app = new App();
app.startApp();
app.stopApp();
app.stopApp();
}
}
  • 这里只需要简单的改变state就可以改变整个类的行为,而无需加入大量if判断。

输出

1
2
3
App Started!
App Stopped!
App Already Stopped!

代理模式

代理模式提供了一个真实对象的替身,来控制对真实对象的访问。被代理的对象可以是远程对象、创建开销大等对象。

创建接口

1
2
3
public interface Image {
void display(String imgName);
}

创建接口实现与代理

1
2
3
4
5
6
public class Icon implements Image {
@Override
public void display(String imgName) {
System.out.println("Display " + imgName);
}
}
1
2
3
4
5
6
7
8
9
10
11
public class IconProxy implements Image {
private Image realIcon;

@Override
public void display(String imgName) {
if (null == realIcon) {
realIcon = new Icon();
}
realIcon.display(imgName);
}
}

使用代理

1
2
3
4
5
6
7
public class App {
public static void main(String[] args) {
Image icon = new IconProxy();

icon.display("Hello");
}
}
用Demo验证ArrayList的线程不安全 细说单例模式中的双重检查锁

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×