Adapter(适配器)
1.基本概念
适配器模式是一种补救模式,将一个类的接口转换成客户希望的另外一个接口。Adapter模式使原本由于接口不兼容而不能一起工作的类可以一起工作。是包装模式(对类或者对象进行包装)的一种,分为类适配器和对象适配器,是从实现层面上划分。
2.三种角色及其关系
- Target目标角色:该角色定义我们要将原接口转化为何种接口,也就是我们期望得到的接口(方便多态地使用)
- Adaptee源角色:需要利用适配器进行包装的原接口
- Adapter适配器:该模式的核心角色,具有将Adaptee包装为Target的职责Adapter改变了Adaptee的接口,使Adaptee和Adapter的基类Target匹配。这样Client就可以把Adaptee当作Target类型来使用。(多态得以实现)
3.Example
(1).我们规定一个情景,A公司要收购B公司,但是他们有两套接口不是很一致的人员管理系统,如下:
- 首先我们给出A公司的接口和实现类(其实重要的只是接口)
interface MyEmployee{
public String getName();
public void setName(String name);
public String getPosition();
public void setPosition( String position );
public String getAddress();
public void setAddress( String address );
public String getAge();
public void setAge( String age );
}
实现类如下,给出实现,只是体现适配器能极大程度忽略内部实现细节。
class EmployeeA implements MyEmployee {//实现MyEmployee接口
private String name;
private String position;
private String address;
private String age;
//应该注意@override注释的必要性,能检查是否为有效的覆盖
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
//TODO 同样的getter和setter
}
- 然而我们的B公司的提供了完全不同的接口和实现方式,B公司将所有的信息存在了一个利用键值对对应的map中
class EmployeeB{
private Map<String,String> basicInfo;
public Map<String, String> getBasicInfo() {
return basicInfo;
}
public void setBasicInfo(Map<String, String> basicInfo) {
this.basicInfo = basicInfo;
}
}
我们采用类适配器来解决这一问题,定义上类适配器应该继承原类,实现目标接口,这样能够达到获得源类的方法,并且采用目标接口的调用形式
class EmployeeAdapter extends EmployeeB implements MyEmployee {
@Override
public String getName() {
return getBasicInfo().get("name");
}
@Override
public void setName(String name) {
Map<String,String> dic = getBasicInfo();
String key = "name";
dic.remove( key);
dic.put( key , name );
}
}
然后我们就可以利用MyEmployee接口同时操作两个公司的员工,并且可以实现多态需要达到的任何操作。
public class adapterEg {
public static void main ( String [] args ){
MyEmployee b = new EmployeeAdapter();
MyEmployee a = new EmployeeA();
//TODO 一系列操作
}
}
(2).
A LegacyRectangle component's display() method expects to receive "x, y, w, h" parameters.
But the client wants to pass "upper left x and y" and "lower right x and y".
a.without Adaptor pattern
b. with Adaptor patter
4.适配器模式的优点
- 能够让两个设计初期没有考虑公用一个接口的类,能够通过添加适配器补救
- 增加了类的透明性,具体实现委托给了源角色,只提供统一的接口
- 使一些类能够在新的设计中得到复用(可以通过适配解决接口不统一的问题)
- 灵活性好,易拓展的同时也方便删改,因为只需要去掉适配器即可,耦合性低,是良好的设计
5.参考文献
https://blog.csdn.net/qq_24451605/article/details/51142715
Decorate(装饰器模式)
1.基本概念
为对象增加不同侧面的特性,对每一个特性构造子类,通过委派机制增加到对象上
2.基本组成及其关系
- Component(组件):组件的抽象,包括装饰者和被装饰者
- Concrete Component(原始组件):被装饰的对象,也就是被装饰者
- Decorator(装饰者):具体的装饰组件的抽象,包含一个抽象component的构件(具体可能是原始组件,也可能是装饰者),继承自Component
- Concrete Decorator:具体的装饰组件,用于实现具体的附加功能。
3.具体事例
package project1;
//Component 组件的抽象
abstract class Component {
public abstract void print();
}
//Decorator 装饰者
abstract class Decorator extends Component{
private Component component;
Decorator( Component component ){
this.component = component;
}
@Override
public void print(){
component.print();
}
}
//ConcreteComponent 原始组件
class Resume extends Component{
@Override
public void print() {
System.out.println("My Name: llin\n"
+"My Major: Software Engineering"
+"My University: Tianjin University"
);
}
}
//ConcreteComponent 具体装饰组件
class AliDecrator extends Decorator{
AliDecrator(Component component) {
super(component);
}
@Override
public void print() {
super.print();
System.out.println("I want a position at Ali major in Java");
}
}
class TencentDecorator extends Decorator{
TencentDecorator(Component component) {
super(component);
}
@Override
public void print(){
super.print();
System.out.println("I want a position at QQ major in C++");
}
}
public class decoratorEg {
public static void main(String[] args) {
Component resume = new Resume();
Component aliResume = new AliDecrator( resume );
Component QQResume = new TencentDecorator( resume );
aliResume.print();
System.out.println("");
QQResume.print();
}
}
My Name: llin
My Major: Software EngineeringMy University: Tianjin University
I want a position at Ali major in Java
My Name: llin
My Major: Software EngineeringMy University: Tianjin University
I want a position at QQ major in C++
4.装饰器模式的优点
- 装饰类和被装饰类可以独立发展,而不会互相耦合,所以具有易维护的特性
- 相对于继承,能够有效地防止子类爆炸,具有易拓展性和易复用性
- 装饰者模式是继承关系的一种替代方案,我们通过例子可以看出,装饰之后返回的依然是Component的接口,实现的是一个is-a的关系。
5.装饰器与适配器模式比较
- 两种模式都是包装模式,都是起到包装一个对象或类的作用
- 适配器的意义在于将一个接口包装成另一个接口,它的目的是通过改变接口达到重复使用的作用
- 装饰器不改变对象的接口,而是恰恰要保持原来的接口,但是增强原有对象的功能,或改变原有对象的处理方法而提升性能。
6.参考文献
https://blog.csdn.net/qq_24451605/article/details/51146084
Facade(外观模式)
1.基本概念
为子系统中的一组接口提供一个统一接口。Facade模式定义了一个更高层的接口,使子系统更加容易使用。
- 我们需要以一种比原有方式更简单直接的办法与系统交互,对于讨论的复杂系统我们只有针对性地使用它的一个子集
- 因为Facade模式可以封装多个子系统,可以减少客户必须处理的对象的数量
- 要求一个子系统的外部与内部的通信必须通过一个统一的对象进行。也就是说Facade对象是外界对于子系统的唯一通道,可以用来整合内部杂乱无章的子系统,不管是否败絮其中,都能做到金玉其外
2.基本组成及其关系
Facade门面对象:
- 此角色知晓子系统的所有功能和责任。
- 一般情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去,也就是该角色没有实际的业务逻辑,只是一个委托类。
- 门面对象一般不参与子系统内的业务逻辑的实现。(只提供一个访问子系统的一个路径而已)
- 作为一个对外的接口,在系统投入运行后,它是不应该被修改的,能够隐藏和封装子系统。
Sub Systems子系统角色:
- 是一个类的集合,但彼此之间可以相互独立,系统之间不存在相互依赖
- 不知道门面对象的存在。
3.具体实例
比如我们平时在使用电脑时,桌面上的文件的快捷方式(或者是一个执行文件),我们需要做的操作只是打开和关闭,通常情况下完全不需要考虑用什么打开啊,设置什么参数啊,关闭的时候应该如何销毁资源才能保证程序的数据能够不造成损失….这个可执行文件就可以看做是一个门面。因为它极大地简化了我们的操作,而且我们可以完全忽略和子系统之间的交互,而简单地认为我是在和一个完整的系统进行交互。
下面提供一个打开文件操作的实现来说明一下,门面模式到底是个什么样:
- Sub Systems:
class OpenWord{
boolean isOpen;
String name = "Viewer";
OpenWord(){
isOpen = false;
}
void open(){
System.out.println("The " + name + " is opening....");
isOpen = true;
}
void stop(){
System.out.println("The " + name + " is closing....");
isOpen = false;
}
}
class PrepareFileSystem{
boolean isOpen;
String name = "FileSystem";
PrepareFileSystem(){
isOpen = false;
}
void open1(){
System.out.println("The " + name + " is opening....");
isOpen = true;
}
void stop1(){
System.out.println("The " + name + " is closing....");
isOpen = false;
}
}
class OperateFile{
void showFile ( String name ){
System.out.println("Show the content of the file: " + name);
}
}
- Facade门面对象
public class OpenFileFacade {
//必须是私有成员,否则会将子系统暴露给外部
private OpenWord openWord = new OpenWord();
private PrepareFileSystem prepareFileSystem = new PrepareFileSystem();
private OperateFile operateFile = new OperateFile();
//只是提供一条访问路径,不实现业务逻辑
public void openFile ( String name ){
prepareFileSystem.open1();
openWord.open();
operateFile.showFile( name );
}
public void closeFile ( String name ){
openWord.stop();
prepareFileSystem.stop1();
}
public static void main ( String [] args ){
OpenFileFacade a = new OpenFileFacade();
a.openFile("cookBook");
a.closeFile("cookBook");
}
}
The FileSystem is opening....
The Viewer is opening....
Show the content of the file: cookBook
The Viewer is closing....
The FileSystem is closing....
4.Facade应用场景
- 为一个复杂的模块或子系统提供一个共外界访问的接口
- 子系统相对独立,外界对子系统的访问只要黑箱操作即可。
- 预防低水平人员带来的风险扩散(解决项目中开发人员的水平差距的问题)
- 降低了个人代码质量对整个项目的影响的风险,一般的做法是画地为牢,只能在指定的子系统中的开发,然后再提供门面接口进行访问。
- 可以针对同一套子系统实现不同的门面类,来方便不同开发者对于子系统的使用,降低接口交流的成本和风险。
5.参考文献
https://blog.csdn.net/qq_24451605/article/details/51242128Strategy(策略模式)
1.基本概念
- 定义一组算法,将每个算法都封装起来,并且他们之间可以互换。
- 使用面向对象的继承和多态机制实现
2.基本组成及关系
- Context封装角色:
它叫做上下文角色,起承上启下的封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。 - Strategy抽象策略角色:
策略,算法家族的抽象,通常为接口,定义每个策略或算法的必须具有的算法和属性。 - Concrete Strategy具体策略角色:
实现抽象策略中的操作,包含具体的算法
3.具体实例
给东西上色
interface Strategy{ //Strategy抽象策略角色: void operate();
}
class RedPaint implements Strategy{//具体策略角色:
@Override
public void operate() {
System.out.println("paint the code to red!");
}
}
class BluePaint implements Strategy{//具体策略角色:
@Override
public void operate() {
System.out.println("Paint the code to blue!");
}
}
class Context{//Context封装角色:
private Strategy strategy;
public Context( Strategy strategy ){
this.strategy = strategy;
}
public void operate ( ){
strategy.operate();
}
}
public class StrategyTest {
public static void main ( String [] args ) {
Context context = new Context(new BluePaint());
context.operate();
context = new Context ( new RedPaint());
context.operate();
}
}
4.Stragegy的优缺点
- 优点:
- 算法可以自由切换,因为具体类的实现不会影响接口的使用,在接口不修改的前提下,具体类可以自由切换(多态)
- 避免多重条件判断,由其他模块决定采取何种策略,策略家族只提供接口
- 拓展性好,可以直接继承共同的接口实现多态来拓展,不需要修改已经存在的类
- 缺点:
- 策略类数量庞大(可以采用装饰模式来防止类数量的爆炸)
- 所有策略类都要对外暴露
5.参考文献
https://blog.csdn.net/qq_24451605/article/details/51331224
Template Method(板块模式)
1.基本概念
模板方法模式就是当我们需要把某些细节层次,但器个别步骤的更详细的实现却是不同的时候,就需要用模板方法模式。实际上就是把一些更详细的信息在子类中去实现,这里更详细的信息就是可变的信息,因为每个子类都不同,所以具有可变信息,然后把不变的行为给他封装到父类中去,这样就去除子类中重复的代码了。step1();
…
step2();
…
step3();
2.基本组成及其关系
3.具体实例
一般我们做系统时都是照着软件工程的思想,就是先做需求分析,然后概要设计,然后详细设计,然后编码,测试,发布这几个步骤,虽然每个系统都不一样,但是我们的工作流程是不变的,只是步骤中某个细节可能会是不同的,如需求分析,不同的系统功能,需求分析肯定是不同的。在工作流程上是不变,而其细节上更详细的设计是可变的,我们就采用模板方法模式。对于不同的系统都采用这个工作流程这套模板来设计。
设计板块
//就是从需求分析到发布系统的一套设计流程
public abstract class DesignCycle {
public abstract void needAnalysis();
public abstract void conceptualDesign();
public abstract void detailedDesign();
public abstract void coding();
public abstract void testSystem();
public abstract void publishSystem();
public void templateDesignSystem(){
System.out.println("------------开始开发----------");
needAnalysis();
conceptualDesign();
detailedDesign();
coding();
testSystem();
publishSystem();
System.out.println("------------开发完毕-----------");
}
}
支付系统具体实现
public class PaymentSystem extends DesignCycle{
@Override
public void needAnalysis() {
// TODO Auto-generated method stub
System.out.println("支付系统的需求分析");
}
@Override
public void conceptualDesign() {
// TODO Auto-generated method stub
System.out.println("支付系统的概要设计");
}
@Override
public void detailedDesign() {
// TODO Auto-generated method stub
System.out.println("支付系统的详细设计");
}
@Override
public void coding() {
// TODO Auto-generated method stub
System.out.println("支付系统的编码");
}
@Override
public void testSystem() {
// TODO Auto-generated method stub
System.out.println("支付系统的测试");
}
@Override
public void publishSystem() {
// TODO Auto-generated method stub
System.out.println("支付系统的发布");
}
}
物流系统具体实现
//物流系统类
public class LogisticSystem extends DesignCycle{
@Override
public void needAnalysis() {
// TODO Auto-generated method stub
System.out.println("物流系统的需求分析");
}
@Override
public void conceptualDesign() {
// TODO Auto-generated method stub
System.out.println("物流系统的概要设计");
}
@Override
public void detailedDesign() {
// TODO Auto-generated method stub
System.out.println("物流系统的详细设计");
}
@Override
public void coding() {
// TODO Auto-generated method stub
System.out.println("物流系统的编码");
}
@Override
public void testSystem() {
// TODO Auto-generated method stub
System.out.println("物流系统的测试");
}
@Override
public void publishSystem() {
// TODO Auto-generated method stub
System.out.println("物流系统的发布");
}
}
测试及其结果
public class Test {
public static void main(String[] args) {
DesignCycle dc;
dc=new PaymentSystem();
dc.templateDesignSystem();
dc=new LogisticSystem();
dc.templateDesignSystem();
}
}
------------开始开发----------
支付系统的需求分析
支付系统的概要设计
支付系统的详细设计
支付系统的编码
支付系统的测试
支付系统的发布
------------开发完毕-----------
------------开始开发----------
物流系统的需求分析
物流系统的概要设计
物流系统的详细设计
物流系统的编码
物流系统的测试
物流系统的发布
------------开发完毕-----------