前言
设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解,本文主要列举了常用的几种设计模式(下篇)。
适配器模式
模式的定义与特点
适配器模式(Adapter
)的定义如下:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式和对象结构型模式两种。
该模式的主要优点如下。
- 客户端通过适配器可以透明地调用目标接口。
- 复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类。
- 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。
模式的结构与实现
1. 模式的结构
适配器模式(Adapter
)包含以下主要角色。
- 目标(
Target
)接口:当前系统业务所期待的接口,它可以是抽象类或接口。 - 适配者(
Adaptee
)类:它是被访问和适配的现存组件库中的组件接口。 - 适配器(
Adapter
)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
类适配器模式的结构图如图 所示
对象适配器模式的结构图如图 所示
2. 模式的实现
(1) 类适配器模式的代码
//目标接口
interface Target
{
public void request();
}
//适配者接口
class Adaptee
{
public void specificRequest()
{
System.out.println("适配者中的业务代码被调用!");
}
}
//类适配器类
class ClassAdapter extends Adaptee implements Target
{
public void request()
{
specificRequest();
}
}
//客户端代码
public class ClassAdapterTest
{
public static void main(String[] args)
{
System.out.println("类适配器模式测试:");
Target target = new ClassAdapter();
target.request();
}
}
结果:
类适配器模式测试:
适配者中的业务代码被调用!
(2)对象适配器模式的代码
//目标接口
interface Target
{
public void request();
}
//适配者接口
class Adaptee
{
public void specificRequest()
{
System.out.println("适配者中的业务代码被调用!");
}
}
//对象适配器类
class ObjectAdapter implements Target
{
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee)
{
this.adaptee=adaptee;
}
public void request()
{
adaptee.specificRequest();
}
}
//客户端代码
public static void main(String[] args)
{
System.out.println("对象适配器模式测试:");
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
}
模式的应用实例
public interface Restaurant {
public void haveFood();
public void haveDrink();
}
public class RestaurantImpl implements Restaurant{
@Override
public void haveFood() {
System.out.println("提供各种美食");
}
@Override
public void haveDrink() {
System.out.println("提供各种饮料");
}
}
public interface Bar {
public void haveSong();
}
public class MyRestaurantAdapter extends RestaurantImpl implements Bar{
@Override
public void haveSong() {
System.out.println("在餐厅同样提供酒吧的驻唱服务");
}
}
public static void main(String[] args) {
MyRestaurantAdapter adapter = new MyRestaurantAdapter();
adapter.haveFood();
adapter.haveDrink();
adapter.haveSong();
}
结果:
提供各种美食
提供各种饮料
在餐厅同样提供酒吧的驻唱服务
模式的应用场景
适配器模式(Adapter
)通常适用于以下场景。
- 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
- 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。
观察者模式
模式的定义与特点
观察者(Observer
)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
观察者模式是一种对象行为型模式,其主要优点如下。
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
- 目标与观察者之间建立了一套触发机制。
模式的结构与实现
1. 模式的结构
观察者模式的主要角色如下。
- 抽象主题(
Subject
)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。 - 具体主题(
Concrete Subject
)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。 - 抽象观察者(
Observer
)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。 - 具体观察者(
Concrete Observer
)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
2. 模式的实现
观察者模式的实现代码
//抽象目标
abstract class Subject
{
protected List<Observer> observers=new ArrayList<Observer>();
//增加观察者方法
public void add(Observer observer)
{
observers.add(observer);
}
//删除观察者方法
public void remove(Observer observer)
{
observers.remove(observer);
}
public abstract void notifyObserver(); //通知观察者方法
}
//具体目标
class ConcreteSubject extends Subject
{
public void notifyObserver()
{
System.out.println("具体目标发生改变...");
System.out.println("--------------");
for(Object obs:observers)
{
((Observer)obs).response();
}
}
}
//抽象观察者
interface Observer
{
void response(); //反应
}
//具体观察者1
class ConcreteObserver1 implements Observer
{
public void response()
{
System.out.println("具体观察者1作出反应!");
}
}
//具体观察者1
class ConcreteObserver2 implements Observer
{
public void response()
{
System.out.println("具体观察者2作出反应!");
}
}
public static void main(String[] args)
{
Subject subject=new ConcreteSubject();
Observer obs1=new ConcreteObserver1();
Observer obs2=new ConcreteObserver2();
subject.add(obs1);
subject.add(obs2);
subject.notifyObserver();
}
结果:
具体目标发生改变...
--------------
具体观察者1作出反应!
具体观察者2作出反应!
模式的应用实例
利用观察者模式设计一个程序,分析“人民币汇率”的升值或贬值对进口公司的进口产品成本或出口公司的出口产品收入以及公司的利润率的影响。
//抽象目标:汇率
abstract class Rate
{
protected List<Company> companys=new ArrayList<Company>();
//增加观察者方法
public void add(Company company)
{
companys.add(company);
}
//删除观察者方法
public void remove(Company company)
{
companys.remove(company);
}
public abstract void change(int number);
}
//具体目标:人民币汇率
class RMBrate extends Rate
{
public void change(int number)
{
for(Company obs:companys)
{
((Company)obs).response(number);
}
}
}
抽象观察者:公司
interface Company
{
void response(int number);
}
//具体观察者1:进口公司
class ImportCompany implements Company
{
public void response(int number)
{
if(number>0)
{
System.out.println("人民币汇率升值"+number+"个基点,降低了进口产品成本,提升了进口公司利润率。");
}
else if(number<0)
{
System.out.println("人民币汇率贬值"+(-number)+"个基点,提升了进口产品成本,降低了进口公司利润率。");
}
}
}
//具体观察者2:出口公司
class ExportCompany implements Company
{
public void response(int number)
{
if(number>0)
{
System.out.println("人民币汇率升值"+number+"个基点,降低了出口产品收入,降低了出口公司的销售利润率。");
}
else if(number<0)
{
System.out.println("人民币汇率贬值"+(-number)+"个基点,提升了出口产品收入,提升了出口公司的销售利润率。");
}
}
}
public static void main(String[] args)
{
Rate rate=new RMBrate();
Company watcher1=new ImportCompany();
Company watcher2=new ExportCompany();
rate.add(watcher1);
rate.add(watcher2);
rate.change(10);
rate.change(-9);
}
结果:
人民币汇率升值10个基点,降低了进口产品成本,提升了进口公司利润率。
人民币汇率升值10个基点,降低了出口产品收入,降低了出口公司的销售利润率。
人民币汇率贬值9个基点,提升了进口产品成本,降低了进口公司利润率。
人民币汇率贬值9个基点,提升了出口产品收入,提升了出口公司的销售利润率。
模式的应用场景
通过前面的分析与应用实例可知观察者模式适合以下几种情形。
- 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
- 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。