哈啰,各位小伙伴们,这里是每天进步一点点的花栗鼠小K
“上期说要补面试经验的空子,就索性写了一下工厂模式。这不,刚写完,小K又回想起了另外两个面试常客:装饰者模式
、代理模式
。之所以说它们是双胞胎,是因为它们真的很像。那接下来,战地记者小K亲自带领大家揭秘这俩兄弟。”
上一节讲到的工厂类模式,属于创建型模式,而今天所介绍的这俩兄弟,则属于另一个山头的,这个山头叫:结构型模式
01
—
结构型模式为何物?
上一节小K提到了创建型模式
,它的主要关注点是『怎样创建对象』。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节,对象的创建由相关的工厂来完成。就像我们去商场购买商品时,不需要知道商品是怎么生产出来一样。它的马仔有5位:单例(Singleton)模式
, 原型(Prototype)模式
, 工厂方法(FactoryMethod)模式
, 抽象工厂(AbstractFactory)模式
, 建造者(Builder)模式
结构型模式
和创建型模式
大相径庭。它关注如何将类或对象按某种布局组成更大的结构。其下可分为两类
类结构型模式:采用继承机制来组织接口和类 对象结构型模式:釆用组合或聚合来组合对象
组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。
合成复用原则:要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现
结构型模式
麾下有七员大将:代理(Proxy)模式
,适配器(Adapter)模式
,桥接(Bridge)模式
,装饰者(Decorator)模式
,外观(Facade)模式
,享元(Flyweight)模式
,组合(Composite)模式
话休烦絮,直接来看这俩兄弟
02
—
装饰者模式
装饰者模式是在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式
其UML
如图
装饰者模式UML
装饰者模式主要包含四个角色
Component
:抽象构件,定义一个抽象接口以规范准备接收附加责任的对象。
ConcreteComponent
:具体构件,实现抽象构件,通过装饰角色为其添加一些职责。
Decorator
:抽象装饰,继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
ConcreteDecorator
:具体装饰,实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
举个🌰,小K为了满足栗子内部成员饮用咖啡的需求,开了一家咖啡店。咖啡的调料一般有方糖、牛奶、摩卡等,不同配料价格不同,如果按照每一种搭配设计一个款式,小K家的价目表会多到爆炸,这个时候如果采用装饰者模式,就可以弹性地应对变化。
小K构建出饮料的抽象类Beverage
(Component
)
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
然后创建两个具体咖啡类 Espresso
和 HouseBlend
(ConcreteComponent
)
public class Espresso extends Beverage {
public Espresso() { description = "Espresso"; }
@Override
public double cost() { return 1.99; }
}
public class HouseBlend extends Beverage{
public HouseBlend() { description = "House Blend Coffee"; }
@Override
public double cost() { return 0.8; }
}
创建调料 CondimentDecorator
抽象类(Decorator
)
public abstract class CondimentDecorator extends Beverage {
private Beverage beverage = null;
@Override
public abstract String getDescription();
}
创建调料 Mocha
和 Soy
类(ConcreteDecorator
)
public class Mocha extends CondimentDecorator{
private Beverage beverage = null;
public Mocha(Beverage beverage) { this.beverage = beverage;}
@Override
public String getDescription() { return beverage.getDescription() + ", Mocha "; }
@Override
public double cost() { return 0.2 + beverage.cost(); }
}
public class Soy extends CondimentDecorator{
private Beverage beverage = null;
public Soy(Beverage beverage) { this.beverage = beverage; }
@Override
public String getDescription() { return beverage.getDescription() + ", Soy ";
}
@Override
public double cost() {
return 0.1 + beverage.cost();
}
}
客户端调用如下
public static void main(String[] args) {
//简单要一杯浓咖啡
Beverage beverage1 = new Espresso();
System.out.println(beverage1.getDescription() + "$" + beverage1.cost());
//两份摩卡加一份豆浆的浓咖啡
Beverage beverage2 = new Espresso();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Soy(beverage2);
System.out.println(beverage2.getDescription() + "$" + beverage2.cost());
//一份摩卡加一份豆浆的黑咖啡
Beverage beverage3 = new HouseBlend();
beverage3 = new Mocha(beverage3);
beverage3 = new Soy(beverage3);
System.out.println(beverage3.getDescription() + "$" + beverage3.cost());
}
这个调用过程,就像是包装礼盒,一层一层的往外包装,比如点两份摩卡一份豆浆的浓咖啡,这一过程的顺序是添加摩卡->添加摩卡->添加豆浆
装饰者模式的优缺点
优点
装饰者是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果 装饰者模式完全遵守开闭原则 缺点
装饰者模式会增加许多子类,过度使用会增加程序得复杂性
03
—
代理模式
代理模式是:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象是不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
其UML
如图
代理模式UML
代理模式主要包含三个角色
Subject
:抽象主题,通过接口或抽象类声明真实主题和代理对象实现的业务方法。
Real Subject
:真实主题,实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
Proxy
:代理,提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
再举个🌰,小K为了多赚一份🌰钱,开办了副业,创建一家公司生产栗子牌电视机。在销售本地需要找到一个代理销售商。那么客户需要购买电视机的时候,就直接通过代理商购买就可以。
TV类代码如下(简单的批爆)
public class TV {
String name;
public TV(String name) {
this.name = name;
}
@Override
public String toString() {
return "TV{" +
"name='" + name + ''' +
'}';
}
}
电视生产公司接口 TVCompany
(抽象主题)
public interface TVCompany {
TV produceTV();
}
电视厂房类 TVFactory
(真实主题)
public class TVFactory implements TVCompany{
@Override
public TV produceTV() {
System.out.println("TV factory produce TV");
return new TV("栗子电视机");
}
}
电视代理商类 TVProxy
(代理)
public class TVProxy implements TVCompany{
private TVFactory tvFactory;
public TVProxy(){
tvFactory = new TVFactory();
}
@Override
public TV produceTV() {
System.out.println("TV proxy get order .... ");
System.out.println("TV proxy start produce .... ");
return tvFactory.produceTV();
}
}
客户端调用如下
public static void main(String[] args) {
TVProxy tvProxy = new TVProxy();
TV tv = tvProxy.produceTV();
System.out.println(tv);
}
每个消费者,都要通过代理商拿到小K家生产的栗子牌电视机
代理模式的优缺点
优点
代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用 代理对象可以扩展目标对象的功能 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性 缺点
代理模式会造成系统设计中类的数量增加
在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢
增加了系统的复杂度
04
—
装饰者模式和代理模式的区别
我们实现的代理模式和装饰者模式十分相像,但他们的目的不同。
通俗来说
代理模式:让别人帮助你做你并不关心的事情,即依赖他人
装饰者模式:为让自己的能力增强,使得增强后的自己能够使用更多的方法,拓展在自己基础之上的功能的,即强化自己
具体区别如下:
前者强调的是增强自身,在被装饰之后你能够在被增强的类上使用增强后的功能。增强后你还是你,只不过能力更强了而已;后者强调要让别人帮你去做一些本身与你业务没有太多关系的职责
前者模式是以对客户端透明的方式扩展对象的功能,是继承方案的一个替代方案;后者则是给一个对象提供一个代理对象,并由代理对象来控制对原有对象的引用
前者是为装饰的对象增强功能;后者对代理的对象施加控制,但不对对象本身的功能进行增强
05
—
总结
本文介绍了面试中常被考察的装饰者模式以及和它相似度极高的代理模式,二者都属于结构型模式。文中从UML
图出发,利用简单的例子加以解释,并详细说明了各自的优劣,最后以二者的区别结尾。本文可以说涵盖了面试考察的全部情况,一定会对即将参加校招的小伙伴有所裨益。
这里是花栗鼠小K,这里是花栗鼠小K,下次有🌰,我再来,拜拜~~~
关注六只栗子,面试不迷路!
作者 花栗鼠小K
编辑 一口栗子
原文始发于微信公众号(六只栗子):听说结构型模式有个双胞胎?
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/88635.html