Java设计模式

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/51242128


Strategy(策略模式)

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();  
    }  
}  
------------开始开发----------
支付系统的需求分析
支付系统的概要设计
支付系统的详细设计
支付系统的编码
支付系统的测试
支付系统的发布
------------开发完毕-----------
------------开始开发----------
物流系统的需求分析
物流系统的概要设计
物流系统的详细设计
物流系统的编码
物流系统的测试
物流系统的发布
------------开发完毕-----------



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值