定义算法簇,分别封装起来,让它们之间可以相互替换,让算法的变化独立于使用算法的客户。
编写各种各样的鸭子类,定义基本的行为呱呱叫(quack)、游泳(swim)、展示(display)。
● 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
应用此设计原则,将fly的实现提取出来,根据飞行的不同,创建多个飞行类代表每种不同的飞行行为。
● 针对接口编程而不是针对对实现编程
如何实现独立出来的飞行方法呢?定义一个FlyBehavior的接口,具体的飞行类都实现此接口,而在Duck中添加此接口的成员,并实现performFly。
public abstract class Duck {
public FlyBehavior flyBehavior;
public void performFly() {
flyBehavior.fly();
}
public abstract void display();
}
public class FakeDuck extends Duck {
public FakeDuck() {
flyBehavior = new FlyNoWay();
}
@Override
public void display() {
System.out.println("fake duck");
}
}
public class NormalDuck extends Duck {
public NormalDuck() {
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
System.out.println("normal duck");
}
}
public interface FlyBehavior {
public void fly();
}
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.out.println("can't fly");
}
}
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("fly with wings");
}
}
观察者模式定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会收到通知并自动更新。
松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的相互依赖降到了最低
实现WeatherData类和对应的布告板类,以实现当WeatherData中的数据发生变化时能够及时通知到布告板。
//主题(可观察者)接口
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
//观察者接口
public interface Observer {
public void update(float temp, float humidity, float perssure);
}
//显示接口
public interface DisplayElement {
public void display();
}
//WeatherData实现
public class WeatherData implements Subject {
private ArrayList<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
//注册观察者
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
//移除观察者
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
//通知观察者数据发生变化
@Override
public void notifyObserver() {
for (Observer o : observers) {
o.update(this.temperature, this.humidity, this.pressure);
}
}
//当气象站得到更新观测值时,通知观察者
public void measurementsChanged(){
notifyObserver();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
//其他方法
}
//布告板实现示例
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData;
//在构造器中调用weatherData进行注册
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
//主题通知时会调用观察者的该方法
@Override
public void update(float temperature, float humidity, float perssure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
@Override
public void display() {
System.out.println("Current Condition is: " + temperature + " F degrees and "
+ humidity + "% humidity");
}
}
//测试,可以在创建多个类型的布告板,这里省略
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
//建立三个布告板
CurrentConditionsDisplay currentCondition1 = new CurrentConditionsDisplay(weatherData);
CurrentConditionsDisplay currentCondition2 = new CurrentConditionsDisplay(weatherData);
CurrentConditionsDisplay currentCondition3 = new CurrentConditionsDisplay(weatherData);
//模拟新的气象测量
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
//结果
Current Condition is: 80.0 F degrees and 65.0% humidity
Current Condition is: 80.0 F degrees and 65.0% humidity
Current Condition is: 80.0 F degrees and 65.0% humidity
Current Condition is: 78.0 F degrees and 90.0% humidity
Current Condition is: 78.0 F degrees and 90.0% humidity
Current Condition is: 78.0 F degrees and 90.0% humidity
使用java.util.Observable
和java.util.Observer
实现观察者模式
import java.util.Observable;
//Observable超类代替我们实现观察者的管理
public class WeatherData2 extends Observable {
private float temperature;
private float humidity;
private float pressure;
public WeatherData2() {
}
//当气象站得到更新观测值时,通知观察者
public void measurementsChanged(){
//在调用notifyObservers()
//需要先调用setChanged()来指示状态已经改变
setChanged();
//没有使用notifyObservers(Object arg),表示采用“拉”的方式获取数据
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
//其他方法
}
import java.util.Observable;
import java.util.Observer;
public class CurrentConditionsDisplay2 implements Observer, DisplayElement {
private Observable observable;
private float temperature;
private float humidity;
//在构造器中调用weatherData进行注册
public CurrentConditionsDisplay2(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
//主题通知时会调用观察者的该方法
@Override
public void update(Observable o, Object arg) {
if(o instanceof WeatherData2) {
WeatherData2 weatherData2 = (WeatherData2) o;
this.temperature = weatherData2.getTemperature();
this.humidity = weatherData2.getHumidity();
display();
}
}
@Override
public void display() {
System.out.println("Current Condition is: " + temperature + " F degrees and "
+ humidity + "% humidity");
}
}
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰着提供了比继承更有弹性的代替方法。装饰者可以在所委托被装饰者的行为之前/或之后,加上自己的行为,以达到特定的目的。
实现不同种类的调料对不同种类的咖啡进行装饰
//饮料抽象类
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
//装饰器抽象类(调料)
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
//Espresso饮料
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
@Override
public double cost() {
return 1.99;
}
}
//HouseBland饮料
public class HouseBland extends Beverage{
public HouseBland() {
description = "HouseBland";
}
@Override
public double cost() {
return 0.89;
}
}
//Mocha调料
//CondimentDecorator继承自Beverage
public class Mocha extends CondimentDecorator{
//用一个实例记录被装饰者
private Beverage beverage;
//把被装饰者通过构造器传递为实例变量中
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
//首先把调用委托给被装饰对象,以计算价钱,然后再加上Mocha的价钱,得到最后结果
return 0.2 + beverage.cost();
}
}
//Soy调料
public class Soy extends CondimentDecorator{
//用一个实例记录被装饰者
private Beverage beverage;
//把被装饰者通过构造器传递为实例变量中
public Soy(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Soy";
}
public double cost() {
//首先把调用委托给被装饰对象,以计算价钱,然后再加上Mocha的价钱,得到最后结果
return 0.15 + beverage.cost();
}
}
//Whip调料
public class Whip extends CondimentDecorator{
//用一个实例记录被装饰者
private Beverage beverage;
//把被装饰者通过构造器传递为实例变量中
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public double cost() {
//首先把调用委托给被装饰对象,以计算价钱,然后再加上Mocha的价钱,得到最后结果
return 0.1 + beverage.cost();
}
}
//测试程序
public class StarbuzzCoffee {
public static void main(String[] args) {
//不进行装饰
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription()
+ " $" + beverage.cost());
//使用三层装饰,生成了也被摩卡,豆浆,奶泡深培
Beverage beverage1 = new HouseBland();
beverage1 = new Mocha(beverage1);
beverage1 = new Soy(beverage1);
beverage1 = new Whip(beverage1);
System.out.println(beverage1.getDescription()
+ " $" + beverage1.cost());
}
}
//结果
Espresso $1.99
HouseBland, Mocha, Soy, Whip $1.34
Java.io 类中也使用了装饰器模式,下面主要几个具体组件和具体装饰器。
下面几个指导方针,能避免在OO设计中违反依赖倒置原则:
简单工厂就是通过传入传入参数的方式,创建不同的对象。(与其说是一种设计模式,不如说是一种编程习惯)
//简单工厂
public class SimplePizzaFactory {
public Pizza createPizza(String type) {
Pizza pizza = null;
if("cheese".equals(type)){
pizza = new CheesePizza();
} else if("pepperoni".equals(type)){
pizza = new PepperoniPizza();
} else if ("clam".equals(type)) {
pizza = new ClamPizza();
} else if ("veggie".equals(type)) {
pizza = new VeggiePizza();
}
return pizza;
}
}
//pizzastore的构造器需要一个工厂作为参数
//而orderPizza()方法,通过简单传入订单类型类使用工厂创建披萨
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory){
this.factory = factory;
}
public Pizza orderPizza(String type) {
Pizza pizza = factory.createPizza(type);
//pizza准备,烘烤。切割,装盒
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
工厂方法模式定义了一个创建对象的接口,但是由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。工厂方法模式能够封装具体类型的实例化。
通过继承抽象类PizzaStore,并实现其createPizza抽象方法用于创造不同类型的Pizza,实现构造不同区域的PizzaStore工厂。
//抽象类PizzaStore
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
//pizza准备,烘烤。切割,装盒
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
//PizzaStore的子类在createPizza处理对象的实例化
protected abstract Pizza createPizza(String type);
}
//PizzaStore的具体实现
public class NYPizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
if ("cheese".equals(type)) {
return new NYStyleCheesePizza();
} else if ("veggie".equals(type)) {
return new NYStyleVeggiePizza();
} else if ("clam".equals(type)) {
return new NYStyleClamPizza();
} else if ("pepperioni".equals(type)) {
return new NYStylePepperioniPizza();
} else{
return null;
}
}
}
从上面代码中可以看到工厂模式的工厂实例中虽然使用类似简单工厂的形式创建的对象,但是他们在本质上却是不一样的
抽象工厂模式提供了一个接口,用于创造相关或依赖对象的家族(一组相关的产品),而不需要明确指明具体类
//抽象工厂接口,其中每个原料都有一个对应的方法创造该原料
public interfacen PizzaIngredientFactory{
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClams();
}
//纽约原料工厂
//为每个区域建造一个原料工厂,并且需要继承自PizzaIngredientFactory,并实现每个方法
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{
public Dough createDough(){
return new ThinCrustDough();
}
public Sauce createSauce(){
return new MarinaraSauce();
}
public Cheese createCheese(){
return new ReggianoCheese();
}
public Veggies[] createVeggies(){
Veggies[] Veggies = {
new Garlic(), new Onion(), new Mushroom(), new RedPepper()};
return Veggies;
}
public Pepperoni createPepperoni(){
return new SlicedPepperoni();
}
public Clams createClams(){
return new FreshClams();
}
}
//其他原料工厂
//...
//抽象Pizza类
public abstract class Pizza {
String name;
Dough dough;
Sauce sauce;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
abstract void prepare();
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}
void box() {
System.out.println("Place pizza in official PizzaStore box");
}
void setName(String name) {
this.name = name;
}
String getName() {
return name;
}
}
//具体的Pizza类
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
//构造函数中传入原料工厂接口,并把这个工厂存储在实例变量中
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
//具体的Pizza类
//...
//在PizzaStore中使用抽象工厂
public class NYPizzaStore extends PizzaStore {
protected Pizza createPizza(String item) {
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory =
new NYPizzaIngredientFactory();
if (item.equals("cheese")) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza");
} else if (item.equals("veggie")) {
pizza = new VeggiePizza(ingredientFactory);
pizza.setName("New York Style Veggie Pizza");
} else if (item.equals("clam")) {
pizza = new ClamPizza(ingredientFactory);
pizza.setName("New York Style Clam Pizza");
} else if (item.equals("pepperoni")) {
pizza = new PepperoniPizza(ingredientFactory);
pizza.setName("New York Style Pepperoni Pizza");
}
return pizza;
}
}