前言
通过学习设计模式的相关课件,阅读《大话设计模式》,了解了常用的七种设计模式:单例模式、工厂方法模式、抽象工厂模式、代理模式、装饰器模式、观察者模式和责任链模式。上一篇博客完成对软件设计模式的概述和前三种设计模式进行学习总结,本篇博客将会对后四种设计模式进行学习总结。
代理模式
定义
由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
静态代理模式
角色分析:
- 抽象角色:一般会使用接口或抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后我们会进行一些附属操作
- 访问角色:访问代理对象的人
静态代理模式:
//租房
public interface Rent {
public void rent();
}
//房东
public class Master implements Rent{
@Override
public void rent() {
System.out.println("房东要租房");
}
}
//中介
public class Proxy implements Rent{
private Master master;
public Proxy() {
}
public Proxy(Master master) {
this.master = master;
}
@Override
public void rent() {
see();
master.rent();
fare();
}
//看房
public void see(){
System.out.println("看房");
}
//收费
public void fare(){
System.out.println("收费");
}
}
//测试
public class Consumer {
public static void main(String[] args) {
Master master=new Master();
//进行代理
Proxy proxy=new Proxy(master);
//不需要通过对象,直接可以通过代理完成操作
proxy.rent();
}
}
可以从上述代码看出,我们通过创建中介这一代理完成了租房,并且还有看房、收费的附属操作。我们不需要使用房东对象,通过使用代理中介就可以完成操作。
代理模式优点:
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
- 公共也就可以交给代理角色!实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理!
代理模式缺点:
一个真实角色就会产生一个代理角色;代码量会翻倍开发效率会变低
也许,这样无法理解到代理模式的好处。举个例子也许能更好理解,比如说我们想要在原有固定功能上新增业务,按照开闭原则我们是不能对原有代码进行修改的。但是我们可以通过代理模式,增加代理,在实现原有功能的情况下写入新的功能,创建对象时也就可以使用代理,完成操作。
动态代理模式
虽然静态代理模式可以很好的解决开闭原则,但是每有一个真实角色就会产生一个代理,代码量翻倍过于臃肿,开发效率较低。因此,我们就使用动态代理模式进行设计。
我们可以使用下面的模板
//自动生成动态代理类模板
public class ProxyInvocationHandler implements InvocationHandler {
//被代理接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
//处理代理类,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(target,args);
return null;
}
}
//使用之前创建的Master类进行测试
public class Consumer {
public static void main(String[] args) {
//真实角色
Master master=new Master();
//代理角色,不存在
ProxyInvocationHandler p=new ProxyInvocationHandler();
//设置代理对象
p.setTarget(master);
//动态生成代理类
Master proxy = (Master) p.getProxy();
proxy.rent();
}
}
通过测试我们可以顺利的使用动态代理模式完成一系列操作,当我们想要添加附属操作时,我们只需要在模板中进行添加。
优点:
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
- 公共也就可以交给代理角色!实现了业务的分工!
- 公共业务发生扩展的时候,方便集中管理!
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可!
装饰者模式
定义
动态的将新功能附加到对象上。在对象功能的拓展方面,比继承更有弹性。同时装饰者模式也体现了开闭原则。
装饰者模式的主要角色
- 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
- 具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
- 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
- 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
实现代码:
//最高层饮料类
public abstract class Drink {
public abstract double cost();
}
//定义果汁具体实现
public class Juice extends Drink {
@Override
public double cost() {
System.out.println("果汁饮料" +4.3);
return 4.3;
}
}
//定义牛奶具体实现
public class Milk extends Drink {
@Override
public double cost() {
System.out.println("牛奶饮料"+3.3);
return 3.3;
}
}
//定义装饰抽象类
public abstract class Decorator extends Drink {
public abstract double cost();
}
//定义装饰具体实现类巧克力
public class Chocolate extends Decorator{
private final static double COST=4;
private Drink drink;
public Chocolate(Drink drink) {
this.drink = drink;
}
@Override
public double cost() {
System.out.println("增加巧克力"+4);
return COST+drink.cost();
}
}
//定义装饰具体实现类布丁
public class Pudding extends Decorator{
private final static double COST = 5;
private Drink drink;
public Pudding(Drink drink) {
this.drink = drink;
}
@Override
public double cost() {
System.out.println("增加布丁"+5);
return COST+drink.cost();
}
}
//测试
public class Test {
public static void main(String[] args) {
Drink milk=new Milk();
milk = new Pudding(milk);
milk = new Chocolate(milk);
System.out.println(milk.cost());
}
}
测试结果:
可以看到非常简单的就能够完成具体构件和具体装饰的组合。
也可以看到结构也非常简洁明了,具体构件在自己的package中,具体装饰也在自己的package中。我们不管是想要增加具体构件还是具体配饰,都可以在各自的package中添加。对已有的代码不需要进行任何操作,就算新加的有bug也不会影响原有代码的操作。
观察者模式
定义
对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式
观察者模式优点
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
- 目标与观察者之间建立了一套触发机制。
实现代码:
//定义观察者接口
public interface Observer {
void response();
}
//具体化观察者1
public class Observer1 implements Observer{
@Override
public void response() {
System.out.println("观察者1作出反应");
}
}
//具体化观察者2
public class Observer2 implements Observer{
@Override
public void response() {
System.out.println("观察者2作出反应");
}
}
//抽象目标
public abstract class Subject {
//创建观察者集合
protected ArrayList <Observer> array = new ArrayList<Observer>();
//增加观察者
public void add(Observer observer){
array.add(observer);
}
//删除观察者
public void remove(Observer observer){
array.remove(observer);
}
//通知观察者方法
public abstract void notifyObserver();
}
//具体化目标
public class Subject1 extends Subject{
@Override
public void notifyObserver() {
for (Observer observer :array){
observer.response();
}
}
}
//测试
public class Test {
public static void main(String[] args) {
Subject subject = new Subject1();
Observer obs1 = new Observer1();
Observer obs2 = new Observer2();
subject.add(obs1);
subject.add(obs2);
subject.notifyObserver();
}
}
测试结果如下:
通过测试我们可以看到,我们不需要建立太多观察者和具体目标之间的联系,大大降低了目标与观察者之间的耦合关系。并且结构也十分简单明了,观察者和目标分别在各自的package包下。当我们想要添加观察者时,只需要在观察者包下进行添加,实现Observer接口就可以了。
责任链模式
定义
一种处理请求的模式,它让多个处理器都有机会处理该诘求,直到其中某个处理成功为止。责任链模式把多个处理器串成链,然后让请求在链上传递。
责任链模式的主要角色
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
责任链模式优点
- 降低了对象之间的耦合度。处理者不需要知道客户的任何信息,客户也不要知道处理者是如何实现方法的。
- 提高了系统的灵活性。当我们想要新增处理器到整个链条中时,所付出的代价是非常小的
责任链模式缺点
- 降低了系统的性能。对比较长的职责链,请求的处理可能涉及多个处理对象
- 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
实现代码:
//抽象处理者
public abstract class Handler {
private Handler next;
public void setNext(Handler next) { this.next = next; }
public Handler getNext() { return next; }
//处理请求
public abstract void handleRequest(int info);
}
//具体处理者1
public class Handler1 extends Handler{
@Override
public void handleRequest(int info) {
if (info <10){
System.out.println("Handler1完成处理");
}else {
if (getNext()!=null){
getNext().handleRequest(info);
}else {
System.out.println("没有处理者进行处理");
}
}
}
}
//具体处理者2
public class Handler2 extends Handler{
@Override
public void handleRequest(int info) {
if (info < 20 && info >10){
System.out.println("Handler2完成处理");
}else {
if (getNext()!=null){
getNext().handleRequest(info);
}else {
System.out.println("没有处理者进行处理");
}
}
}
}
//测试
public class Test {
public static void main(String[] args) {
Handler handler1 = new Handler1();
Handler handler2 = new Handler2();
handler1.setNext(handler2);
handler1.handleRequest(5);
handler1.handleRequest(15);
handler1.handleRequest(25);
}
}
测试结果如下:
通过测试结果我们看到,5交给了Handler1处理,15交给了Handler2处理,而25则没有处理者处理。请求者根本不需要参与处理,只需要提交数据就可以完成功能的处理,完全不需要管是哪个处理者进行处理的。当我们想要继续添加处理者时,这只需要再次添加就可以了,也不会对之前的代码造成影响。
总结
到此,已经完成了对七种常见设计模式的学习总结。但是,在学习和使用设计模式甚至是程序员学习的道路才刚刚开始,学习的知识越多会让我觉得自己的渺小,也会让我更加虚心的去学习。