提示:本章节为《java面试系列》
类似章节:java中设计模式
设计模式2
设计模式3
设计模式4
1. 说明
本文主要介绍抽象工厂,观察者,策略,装饰。其他的模式,后面看情况再总结。
2. 介绍顺序
抽象工厂
观察者
策略
装饰
3. 正文
- 抽象工厂
提供一个用来创建一个产品家族的抽象类型,这个类型的子类定义了产品被生产的方法。
当需要创建产品家族和想让制造的相关产品集合起来时,就可以使用该模式。
类图+解释:
抽象工厂模式创建很多对象的而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大不同。
抽象工厂模式用到了工厂方法模式来创建单一对象,AbstractFactory 中的 createProductA() 和 createProductB() 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂方法模式的定义。
至于创建对象的家族这一概念是在 Client 体现,Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象,在这里这两个对象就有很大的相关性,Client 需要同时创建出这两个对象。
从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory,而工厂方法模式使用了继承。如下图:
代码实现:
class AbstractProductA {
}
class AbstractProductB{
}
class ProductA1 extends AbstractProductA {
}
class ProductA2 extends AbstractProductA {
}
class ProductB1 extends AbstractProductB{
}
class ProductB2 extends AbstractProductB{
}
abstract class AbstractFactory {
abstract AbstractProductA createProductA();
abstract AbstractProductB createProductB();
}
class ConcreateFactory1 extends AbstractFactory{
@Override
AbstractProductA createProductA() {
return new ProductA1();
}
@Override
AbstractProductB createProductB() {
return new ProductB1();
}
}
class ConcreateFactory2 extends AbstractFactory{
@Override
AbstractProductA createProductA() {
return new ProductA2();
}
@Override
AbstractProductB createProductB() {
return new ProductB2();
}
}
public class Client {
public static void main(String[] args) {
AbstractFactory abstractFactory =new ConcreateFactory1();
AbstractProductA productA = abstractFactory.createProductA();
AbstractProductB productB = abstractFactory.createProductB();
}
}
- 观察者模式
定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。如下图所示:(出版者+订阅者=观察者模式)
类图+解释:
主题(Subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。
观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。如下图:
代码实现:
天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。如下图:(图只画出其中一个)
import java.util.ArrayList;
import java.util.List;
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObserver();
}
class WeatherData implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
notifyObserver();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(i);
}
}
@Override
public void notifyObserver() {
for (Observer o : observers) {
o.update(temperature, humidity, pressure);
}
}
}
interface Observer {
void update(float temp, float humidity, float pressure);
}
class StatisticsDisplay implements Observer {
public StatisticsDisplay(Subject weatherData) {
weatherData.registerObserver(this);
}
@Override
public void update(float temp, float humidity, float pressure) {
System.out.println("StatisticsDisplay.update: " + temp + " " + humidity + " " + pressure);
}
}
class CurrentConditionsDisplay implements Observer {
public CurrentConditionsDisplay(Subject weatherData) {
weatherData.registerObserver(this);
}
@Override
public void update(float temp, float humidity, float pressure) {
System.out.println("CurrentConditionsDisplay.update: " + temp + " " + humidity + " " + pressure);
}
}
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay current = new CurrentConditionsDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
weatherData.setMeasurements(30, 30, 30);
weatherData.setMeasurements(100, 100, 100);
}
}
输出:
- 策略模式
定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
类图+解释:
Strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。
Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。如下图所示:
与状态模式的比较:
状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。
代码实现:
interface QuackBehavior{
void quack();
}
class Quack implements QuackBehavior{
@Override
public void quack() {
System.out.println("呱呱呱");
}
}
class Squeak implements QuackBehavior{
@Override
public void quack() {
System.out.println("叽叽叽");
}
}
class Duck{
private QuackBehavior quackBehavior;
public void performQuack(){
if (quackBehavior != null){
quackBehavior.quack();
}
}
public void setQuackBehavior(QuackBehavior quackBehavior){
this.quackBehavior = quackBehavior;
}
}
public class Client2 {
public static void main(String[] args) {
Duck duck = new Duck();
duck.setQuackBehavior(new Squeak());
duck.performQuack();
duck.setQuackBehavior(new Quack());
duck.performQuack();
}
}
输出:
- 装饰模式
为对象动态添加功能。
假设咖啡店中顾客想要摩卡和奶泡深焙咖啡:
类图+解释:
装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。如下所示:
代码实现:
下图表示在 DarkRoast 饮料上新增新添加 Mocha 配料,之后又添加了 Whip 配料。DarkRoast 被 Mocha 包裹,Mocha 又被 Whip 包裹。它们都继承自相同父类,都有 cost() 方法,外层类的 cost() 方法调用了内层类的 cost() 方法。
interface Beverage {
double cost();
}
class DarkRoast implements Beverage{
@Override
public double cost() {
return 1;
}
}
class HouseBlend implements Beverage{
@Override
public double cost() {
return 1;
}
}
abstract class CondimentDecorator implements Beverage {
protected Beverage beverage;
}
class Milk extends CondimentDecorator{
public Milk(Beverage beverage){
this.beverage = beverage;
}
@Override
public double cost() {
return 1 + beverage.cost();
}
}
class Mocha extends CondimentDecorator{
public Mocha(Beverage beverage){
this.beverage = beverage;
}
@Override
public double cost() {
return 1+beverage.cost();
}
}
public class Client3 {
public static void main(String[] args) {
Beverage beverage = new HouseBlend();
beverage = new Mocha(beverage);
beverage = new Milk(beverage);
System.out.println(beverage.cost());
}
}
小编不才,欢迎大家指出不正确的地方!