1、适配器模式:
定义:将一个类的接口转换为客户希望的另一个类的接口,适配器模式使得原本由于接口不兼容的那些类可以一起工作;
简单说明:它主要是实现接口转换;是原本不兼容的事物能够协同工作,而无须修改现有事物的内部结构;
这个模式也很简单,笔记本上的那个拖在外面的黑盒子就是个适配器,一般你在中国能用,在日本也能用,虽然两个国家的的电源电压不同,中国是 220V,日本是 110V,但是这个适配器能够把这些不同的电压转换为你需要的 36V 电压,保证你的笔记本能够正常运行;
适配器模式又分为类适配器模式和对象适配器模式:
类适配器模式就是适配器类和适配者类是继承关系,而对象适配适配器模式就是适配器类和适配者类是关联关系;
模式结构图;
- Target(目标抽象类):抽象类定义客户要用的特定领域的接口,可以是抽象类或接口或者是类;
- Adapter(适配器类):适配器类可以调用另一个接口,接口作为一个转换器,对适配者类和目标类进行适配;
- Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下甚至没有适配者类的源代码;
- Client(客户类):在客户类中针对目标抽象类进行编程,调用在目标抽象类中定义的业务方法;
类适配器模式结构:
对象适配器模式结构图:
类适配器模式和对象适配器的区别就在于适配器类和适配者类之间的关系是继承(类适配器模式)还是依赖(对象适配器模式);
比如现在有一个抽象类,它里面有绘制点、线、方块的方法,而为了让客户在使用这些接口的时候不用关心它们底层调用的不同,我们还使用了一个抽象类来规范这些图形的接口,现在我们需要绘制一个圆,并且发现已有一个类里面有绘制圆的方法,但是这个方法名和我们抽象类规定的方法名称不符,这个时候如果去修改绘制圆的方法名,那就要修改所有引用该方法的地方,修改抽象方法名,那也要修改所有的实现类,都很麻烦,要解决这样的麻烦,就要用我们的适配器模式了:
/**
* @ClassName Shape
* @Description 形状类
* @Date 2019/3/17 11:21
* @Version 1.0
**/
public abstract class Shape {
/**
* 绘制点的方法
*/
public void draw_dot() {
System.out.println("绘制点");
}
/**
* 绘制线的方法
*/
public void draw_wire() {
System.out.println("绘制线");
}
/**
* 绘制方块的方法
*/
public void draw_block() {
System.out.println("绘制方块");
}
/**
* 绘制圆的方法
*/
public abstract void draw_circle();
}
/**
* @ClassName Circle
* @Description 与圆相关的类,里面有绘制圆的方法
* @Author lzq
* @Date 2019/3/17 11:23
* @Version 1.0
**/
public class Circle {
private int r = 0; //圆的半径
/**
* 绘制圆的方法
*/
public void draw() {
System.out.println("绘制圆");
}
/**
* 设计半径方法
* @param r
*/
public void setR(int r) {
this.r = r;
}
/**
* 计算圆的面积
* @return
*/
public double area() {
return Math.PI*r*r;
}
/**
* 计算圆的周长
* @return
*/
public double perimeter() {
return 2*Math.PI*r;
}
}
/**
* @ClassName ShapeCircle
* @Description 绘制圆的类
* @Author lzq
* @Date 2019/3/17 11:40
* @Version 1.0
**/
public class ShapeCircle extends Shape{
private Circle circle; //这里引用了Circle类
public ShapeCircle() {
circle = new Circle(); //初始化
}
/**
* 绘制圆的法
*/
public void draw_circle() {
circle.draw(); //调用Circle里面的对应方法
}
}
适配器模式的优缺点:
优点:
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无需修改原来的代码;
- 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端来说是透明的,而且提高了适配者的复用性;
- 灵活性和扩展性都非常好,通过使用配置文件,可以很方便的更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,符合开闭原则;
- 对象适配器模式的优点还有:对象适配器模式可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口;
缺点:
类适配器的缺点:
对于不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为接口,不能为类,其使用有一定的局限性,不能将一个适配者类和它的子类同时适配到目标接口;
对象适配器的缺点:
与类适配器模式相比,要想置换适配者类的方法就不容易,如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当作真正的适配者进行适配,实现过程较为复杂;
2、观察者模式:
定义:定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖与它的对象都得到通知并自动刷新;
说明:一个对象的行为将影响到一个或多个其他对象的其他对象的行为;
①Subject(目标):目标又称为主题,指被观察的对象;在目标中定义了一个观察者集合,它可以存储任意数量的观察者对象,它提供了一个接口来增加和删除观察者对象,同时它定义了通知方法,目标类可以是接口,也可以是抽象类或者实现类。
②ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含经常发生改变的数据,当他的状态发生改变时,向他的各个观察者发出通知;同时他还实现类来目标类中定义的抽象业务逻辑方法(如果有的话);
③Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法,因此又称为抽象观察者;
④ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;
实例:假设猫是老鼠和狗的观察目标,老鼠和狗是观察者,猫叫老鼠跑,狗也跟着叫,使用观察者模式描述该过程;
代码:
import java.util.ArrayList;
/**
* @ClassName MySubject
* @Description 抽象目标类(MySubject)
* @Author lzq
* @Date 2019/6/5 16:15
* @Version 1.0
**/
public abstract class MySubject {
protected ArrayList observers = new ArrayList();
/**
* 添加方法
* @param myObServer
*/
public void attach(MyObserver myObServer) {
observers.add(myObServer);
}
public void detach(MyObserver myObserver){
observers.remove(myObserver);
}
//通知方法
public abstract void cry();
}
/**
* @ClassName MyObserver
* @Description 抽象观察者
* @Author lzq
* @Date 2019/6/5 16:18
* @Version 1.0
**/
public interface MyObserver {
void response(); //抽象响应方法
}
/**
* @ClassName Cat
* @Description 具体目标类 猫
* @Author lzq
* @Date 2019/6/5 16:20
* @Version 1.0
**/
public class Cat extends MySubject{
@Override
public void cry() {
System.out.println("猫叫!");
System.out.println("-------------------------");
for (Object o : observers) {
((MyObserver)o).response();
}
}
}
/**
* @ClassName Mouse
* @Description 具体观察者类 老鼠
* @Author lzq
* @Date 2019/6/5 16:22
* @Version 1.0
**/
public class Mouse implements MyObserver{
@Override
public void response() {
System.out.println("老鼠飞快逃跑...");
}
}
/**
* @ClassName Dog
* @Description 具体观察者类 狗
* @Author lzq
* @Date 2019/6/5 16:23
* @Version 1.0
**/
public class Dog implements MyObserver{
@Override
public void response() {
System.out.println("狗跟着叫...");
}
}
/**
* @ClassName Client
* @Description 测试类
* @Author lzq
* @Date 2019/6/5 16:24
* @Version 1.0
**/
public class Client {
public static void main(String[] args) {
MySubject subject = new Cat();
MyObserver obs1,obs2,obs3;
obs1 = new Mouse();
obs2 = new Mouse();
obs3 = new Dog();
subject.attach(obs1);
subject.attach(obs2);
subject.attach(obs3);
subject.cry();
}
}
运行结果: