-
装饰模式
装饰(decorator)模式指的是在不改变原类文件和不使用继承的情况下,它是通过创建一个包装类,动态地扩展一个对象的功能。
装饰模式结构图
示例:
将一个Person对象通过包装类Decorator包装成含有各个属性(高、富、帅)的对象。
定义Person接口:
interface Person {
void show();
}
需要进行合成的类:
class ConcreatePerson implements Person {
@Override
public void show() {
System.out.println("人");
}
}
抽象的装饰类:
/**
* 创建Decorator类,持有Person对象,对Person的实例进行包装
*/
abstract class Decorator implements Person {
protected Person person;
public Decorator(Person person) {
this.person = person;
}
@Override
public abstract void show();
}
分别是高、富、帅的包装类:
class HeightDecorator extends Decorator {
public HeightDecorator(Person person) {
super(person);
}
@Override
public void show() {
height();
person.show();
}
/**
* 去修饰高属性
*/
public void height() {
System.out.println("高");
}
}
class RichDecorator extends Decorator {
public RichDecorator(Person person) {
super(person);
}
@Override
public void show() {
rich();
person.show();
}
public void rich() {
System.out.println("富");
}
}
class PrettyDecorator extends Decorator {
public PrettyDecorator(Person person) {
super(person);
}
@Override
public void show() {
pretty();
person.show();
}
public void pretty() {
System.out.println("帅");
}
}
创建客户端执行测试:
public static void main(String[] args) {
//因为具体的Person和Decorator都继承过Person接口,所有两者可以相互替换
//创建对象,创建需要的包装类,连续将包装过的装饰者继续装饰
Person concreatePerson = new ConcreatePerson();
Decorator decorator = new HeightDecorator(concreatePerson);
Decorator decorator1 = new RichDecorator(decorator);
Decorator decorator2 = new PrettyDecorator(decorator1);
decorator2.show();
}
打印结果:concreatePerson这个普通人在经过HeightDecorator、RichDecorator和PrettyDecorator三个装饰器包装之后,成为了一个高富帅。
装饰模式特点:
1.装饰对象和真实对象有相同的接口。这样调用者就能以和真实对象相同的方式与装饰对象交互。
2.装饰对象包含一个真实对象的引用。
3.装饰对象接受所有来自客户端的请求,它把这些请求转发给真实的对象。
装饰模式有缺点:
装饰模式和继承关系的目的都是要扩展对象的功能,但是Decorator可以比继承更加灵活,可以使用这些装饰类进行排列组合创造出很多不同行为的组合。
但是更灵活的代价是会创建很多装饰类,增加了更多的复杂性。
-
代理模式
代理模式可以可以为其他对象提供一种代理以控制这个对象的访问。
代理模式结构图
Subject(抽象接口):真实主题与代理主题的共同接口。
RealSubject(目标类):定义了代理角色所代表的真实对象。
Proxy(代理类):含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真实主题对象之前或之后执行某些操作,而不是单纯返回真实的对象。
示例:
Customer类为需要打官司的顾客,Lawyer为律师类,Lawyer类需要代理Customer打官司。
定义代理类与目标类共同的接口:
interface Law {
//定义一个打官司的接口,需要实现打官司
void law();
}
目标类:某个客户需要打官司
class Customer implements Law {
@Override
public void law() {
System.out.println("上法庭陈述事实");
}
}
代理类:律师,需要打官司,可以搜集证据,代理客户打官司
class Lawyer implements Law {
private Customer customer;
public Lawyer(Customer customer) {
this.customer = customer;
}
/**
* 陈述事实却需要当事人自己在法庭上陈述,自己调用law
*/
@Override
public void law() {
collEvidence();
//目标类调用自己方法
customer.law();
over();
}
/**
* 律师可以做搜集证据
*/
public void collEvidence() {
System.out.println("搜集证据");
}
/**
* 律师可以尽量打赢官司
*/
public void over() {
System.out.println("打赢官司");
}
}
执行测试,律师代理客户打官司:
public static void main(String[] args) {
Customer customer = new Customer();
Lawyer lawyer = new Lawyer(customer);
lawyer.law();
}
上面例子的代理方法是静态代理。加入有多个Customer具体目标类,每个目标类需要代理的law方法都不同,有的要打婚姻官司,有的打经济官司,有的打合同违约官司,那么就需要创建多个代理类,在内部去调用law1、law2、law3方法等。
动态代理:
见我的另一篇文章动态代理实战
-
适配器模式
Adapter模式可以改变已有类(或外部类)的接口形式。
模式结构图:
示例:
场景需要18v的Target电压,但是总线是220v的Adapee电压,那么就需要一个适配器Adapter将220v的电压转为18v的电压。
Target类:
interface Target {
void v18();
}
目标电压:
class Adapee220 {
public void show() {
System.out.println("输出220v电压");
}
}
适配器Adapter类:
class Adapter implements Target {
private Adapee220 adapee220;
public Adapter(Adapee220 adapee220) {
this.adapee220 = adapee220;
}
@Override
public void v18() {
adapee220.show();
System.out.println("实现将220v电压转化为18v");
}
}
执行测试:
public static void main(String[] args) {
Adapee220 adapee220 = new Adapee220();
Target target = new Adapter(adapee220);
target.v18();
}
转化结果: