JAVA 的23中设计模式之二:结构型模式

分类:

创建型模式(关注对象的创建过程):

               单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。

结构型模式(关注对象和类的组织):

               适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。

行为型模式(关注对象之间的交互,研究运行时对象之间的通信协作):

               模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、

               策略模式、职责链模式、访问者模式。

 

 

1,适配器模式(adapter):

概念:

         将一个类的接口转换成客户希望的另一个接口,使不兼容转换为可以一起工作。

角色:

  •    目标接口(Target):客户期待的接口。
  •     需要适配的类(Adaptee):提供给适配器的类。
  •     适配器(Adapter): 通过包装一个需要适配的对象,把原接口转换成目标接口。

使用场景:

           经常用来做旧系统改造和升级,开发新的模块并且以适配器的模式来兼容旧系统时的模块。

            常用的类有: java.io.InputStreamReader(InputStream),java.io.InputStreamWriter(OutputStream)

适配器模式实现:

        举个例子:

      比如 iphone7手机没有 耳机插孔 如果想用 有线耳机  则需要一个 转换器  来适配手机充电口和耳机插口。

        1,类适配器方法:

1、
/**
 * 被适配对象(如图中:耳机)
 */
public class Adaptee {
    public void request(){
        System.out.println("可以完成客户需要的功能。。。");
    }
}

2、
/**
 * 适配接口
 */
public interface Target {
    void handlerReq();
}

3、
/**
 * 适配器类( 如图中:转换器)
 */
public class Adapter extends Adaptee implements Target{

    public void handlerReq() {
            super.request();
    }
}

4、
/**
 * 调用者(如图中:手机)
 */
class Client {
    //测试方法
    public void test(Target t) {
        t.handlerReq();
    }

    //执行
    public static void main(String[] args) {
        // 整个流程: 调用者去 接入 适配器,适配器去 接入 被适配对象
        Client c = new Client();

        c.test(new Adapter());

    }
}

 

    2,对象适配器方法: 

1、
/**
 * 被适配对象(如图中:耳机)
 */
public class Adaptee {
    public void request(){
        System.out.println("可以完成客户需要的功能。。。");
    }
}

2、
/**
 * 适配接口
 */
public interface Target {
    void handlerReq();
}

3、
/**
 * 适配器类( 如图中:转换器)
 */
public class Adapter  implements Target{
    public Adaptee adaptee;

    public Adapter(Adaptee adaptee){
        super();
        this.adaptee = adaptee;
    }

    public void handlerReq() {
        adaptee.request();
    }
}

4、
/**
 * 调用者(如图中:手机)
 */
class Client {
    //测试方法
    public void test(Target t) {
        t.handlerReq();
    }

    //执行
    public static void main(String[] args) {
        // 整个流程: 调用者去 接入 适配器,适配器去 接入 被适配对象
        Client c = new Client();
        c.test(new Adapter(new Adaptee()));

    }
}

 

2,代理模式(Proxy pattern):

概念:

          通过代理,控制对对象的访问,控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。AOP(面向切面编程)的核心实现就是代理模式。

角色:

  •    抽象角色:定义代理角色和真实角色的公共对外方法。
  •    真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
  •    代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务方法来实现抽象方法,并可以附加自己的操 作。                                      

使用场景:

  •    安全代理:屏蔽对真实角色的直接访问。 
  •    远程代理:通过代理类处理远程方法的调用(RMI)。 
  •    延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。

分类:

  •    静态代理:代理类由手动自己创建。
  •    动态代理: 由程序自动生成代理方法。(JDK自带动态代理,javaassist字节码操作库实现,CGLIB...)

代理对象实现:

    1,静态代理:

1、
public interface Star {
    //面谈
    void confer();
    //签合同
    void bookTicket();
    //唱歌
    void sing();
    //收钱
    void collectMoney();
}


2、
/**
 * 真实角色
 */
public class RealStar implements Star {
    public void confer() {
        System.out.println("真实:RealStar.confer()");
    }

    public void bookTicket() {
        System.out.println("真实:RealStar.bookTicket()");
    }

    public void sing() {
        System.out.println("真实:RealStar.sing()");
    }

    public void collectMoney() {
        System.out.println("真实:RealStar.collectMoney()");
    }
}


3、
/**
 * 代理对象
 */
public class ProxyStar implements Star {

    private Star realStar;

    public ProxyStar(Star realStar) {
        this.realStar = realStar;
    }

    public void confer() {
        System.out.println("代理:ProxyStar.confer()");
    }

    public void bookTicket() {
        System.out.println("代理:ProxyStar.bookTicket()");
    }

    public void sing() {
        // TODO 需求:代理对象需要执行真实角色中的 sing() 方法
        realStar.sing();
    }

    public void collectMoney() {
        System.out.println("代理:ProxyStar.collectMoney()");
    }

    public static void main(String[] args) {
        //真实角色
        Star realStar = new RealStar();
        //代理角色
        Star proxyStar = new ProxyStar(realStar);
        //以代理对象方式,执行真实角色中的 sing() 方法
        proxyStar.sing();
    }
}

   2,动态代理: 

          JDK自带动态代理:

  •           java.lang.reflect.Proxy:动态生成代理类和对象(每次生成的代理类对象都要指定对应的处理器对象)
  •           java.lang.reflect.InvocationHandler:可通过invoke方法实现对真实对象代理访问。

 

1、

public interface Star {
    //面谈
    void confer();
    //签合同
    void bookTicket();
    //唱歌
    void sing();
    //收钱
    void collectMoney();
}

2、
/**
 * 真实角色
 */
public class RealStar implements Star {
    public void confer() {
        System.out.println("真实:RealStar.confer()");
    }

    public void bookTicket() {
        System.out.println("真实:RealStar.bookTicket()");
    }

    public void sing() {
        System.out.println("真实:RealStar.sing()");
    }

    public void collectMoney() {
        System.out.println("真实:RealStar.collectMoney()");
    }
}

3、
public class StarHandler implements InvocationHandler {

    private Star realStar;

    public StarHandler(Star realStar) {
        this.realStar = realStar;
    }


    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //执行你调用的方法
        System.out.println("######方法开始#####");
        method.invoke(realStar ,args);
        System.out.println("######方法结束#####");
        return null;
    }

    public static void main(String[] args){

        //代理处理类
        StarHandler proxyHandler = new StarHandler(new RealStar());
        //动态生成 代理角色
        Star proxy = (Star)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class},proxyHandler);

        proxy.confer();
        proxy.sing();
        System.out.println();
    }
}

           动态代理开发场景:

  •            Struts2 中拦截器的实现
  •             数据库连接池关闭处理
  •             Mybatis实现拦截器插件
  •             Spring中的AOP的实现(日志拦截,声明式事务)
  •             RMI远程方法调用

 

 

 

 

3,组合模式(composite):

概念:

         把部分和整体的关系用树形结构来标识,从而使客户端可以使用同一的方式处理部分对象和整体对象。

         (主要是为了处理树形结构而应用的模式。)

组合模式核心:

  •          抽象构件(Component):定义了叶子和容易构件的共同点。
  •          叶子构件(Leaf):无子节点。
  •          容器构件:有容器特征,可以包含子节点。

 应用场景:

  •         GUI中的容器层次图。
  •          XML文件解析。
  •          Junit单元测试框架。(底层设计就是组合模式)

举例实现:

1、
//抽象构件
public interface AbstractFile {
    void  recursion(); //递归打印
}

class VideoFile implements AbstractFile {
    private String name;
    public VideoFile(String name) {
        this.name = name;
    }
    public void recursion() {
        System.out.println("--视频文件:"+name+"---");
    }
}

 class ImageFile implements AbstractFile {
    private String name;
    public ImageFile(String name) {
        this.name = name;
    }
    public void recursion() {
        System.out.println("--图像文件:"+name+"---");
    }
}

class Folder implements AbstractFile{
    private String name;
    private List<AbstractFile> list = new ArrayList<AbstractFile>();

    public Folder(String name) {
        this.name = name;
    }

    public void add(AbstractFile file){
        list.add(file);
    }
    public void remove(AbstractFile file){
        list.remove(file);
    }
    public void getChild(int index){
        list.get(index);
    }

    //递归方法实现
    public void recursion() {
        System.out.println("--文件夹:"+name+"---");
        for (AbstractFile file : list) {
            file.recursion();
        }
    }

}

2、
public class Client {
    public static void main(String[] args) {
        Folder f1 = new Folder("我的收藏");
        f1.add(new ImageFile("大胖的肌肉.jpg") {
        });
        f1.add(new VideoFile("大胖和国家的二三事.AVI"));

        //将 我的收藏2 文件夹存入 大胖的肌肉实在不得了.jpg和大胖和宇宙的二三事.AVI
        //再把  我的收藏2 放入 我的收藏 中
        Folder f11 = new Folder("我的收藏2");
        f11.add(new ImageFile("大胖的肌肉实在不得了.jpg") {
        });
        f11.add(new VideoFile("大胖和宇宙的二三事.AVI"));

        f1.add(f11);
        f1.recursion();
        System.out.println();
    }
}

 

 

 

4,装饰器模式(decorator):

 概念:

          也叫包装器模式(Wrapper),动态的为一个对象增加或删除对象的功能,是一种代替继承的技术。无需通过继承增加子类就能扩展对象的新功能。

          (比如 一个屋子(相当于:new的对象),可对这个屋子 装灯具,壁纸等一系列的装饰便是装饰器模式)

优点:

         使用装饰模式灵活的使对象的关联关系代替了继承关系,避免类与类之间的继承关系过于复杂。

缺点:

         产生很多小对象,大量小对象占据内存,影响性能。并且易于出错,调试排查麻烦。

组件核心:

  •   Component 抽象构件角色: 真实对象和装饰对象相同的接口,这样客户端对象就能以真实对象相同的方式同装饰对象交互。
  •   ConcreteComponent 具体构件角色(真实对象):  io流中的FileInputStream,FileOutputStream
  •   Decorator装饰器角色: 先实现 抽象构件角色,让所有调用者请求转发给真实的对象。
  •    ConcreteDecorator具体装饰角色: 负责给构件对象增加新的责任。

举例实现:


1、
/**
 * 抽象组件
 */
public interface ICar {
    void move();
}

// ConcreteComponent 具体构件角色(真实对象)
class Car implements  ICar{
    public void move() {
        System.out.println("汽车在陆地上跑!");
    }
}

// 装饰器角色
class SuperCar implements ICar{
    private ICar car;
    public SuperCar(ICar car) {
        this.car = car;
    }
    public void move() {
        car.move();
    }
}

//为真实对象提供的装饰品(ConcreteDecorator具体装饰角色)
class FlyCar extends SuperCar{
    public FlyCar(ICar car) {
        super(car);
    }
    public void fly(){
        System.out.println("为 Car 添加飞行功能");
    }
    @Override
    public void move() {
        super.move();
        fly();
    }
}
//为真实对象提供的装饰品(ConcreteDecorator具体装饰角色)
class WaterCar extends SuperCar{
    public WaterCar(ICar car) {
        super(car);
    }
    public void water(){
        System.out.println("为 Car 添加水上游功能");
    }
    @Override
    public void move() {
        super.move();
        water();
    }
}
//为真实对象提供的装饰品(ConcreteDecorator具体装饰角色)
class AICar extends SuperCar{
    public AICar(ICar car) {
        super(car);
    }
    public void AI(){
        System.out.println("为 Car 添加智能功能");
    }
    @Override
    public void move() {
        super.move();
        AI();
    }
}



2、
public class Test {

    public static void main(String[] args){
        System.out.println("【为添加装饰前:】");
        Car c =new Car();
        c.move();
        System.out.println();

        //添加单个装饰品
        System.out.println("【添加飞行功能:】");
        FlyCar flyCar = new FlyCar(c);
        flyCar.move();
        System.out.println();

        //添加多个装饰品
        System.out.println("【添加飞行 , 水上游 , 智能 功能:】");
        AICar aiCar = new AICar(new WaterCar(new FlyCar(c)));
        aiCar.move();
    }
}

         概略图:

使用场景:

  •      IO中的输入流和输出流设计。
  •       Servlet API中提供了一个request对象的Decorator设计模式的默认实现类 HttpServletRequestWrapper、HttpServletRequestWrapper类,增加了request对象的功能。

5,外观模式:

 核心:

         其实就是封装对象,为调用者提供便携的入口,减少调用者调用时的复杂性。

举例实现:

         比如:如果没有汽车商家的话,想购车需要联系厂家买车,联系银行上车险,跑去税务局交税之类的...外观模式的核心就是把繁琐的步骤封装起来,只提供汽车商家供用户购买汽车,其他事宜全都代办。

public class Merchant{
    public void BugCar(){
        AutoMakers autoMakers = new AutoMakers();
        autoMakers.getCar();
        Bank bank = new Bank();
        bank.insurance();
        TheRevenue theRevenue = new TheRevenue();
        theRevenue.tax();
    }
}
class AutoMakers {
    public void getCar(){
        System.out.println("从厂家获取汽车");
    }
}
class Bank{
    public void insurance(){
        System.out.println("为汽车上保险");
    }
}
class TheRevenue{
    public void tax(){
        System.out.println("为汽车交税");
    }
}

class Client{

    public static void main(String[] args){
        Merchant merchant =new Merchant();
        merchant.BugCar();
    }
}

 

6,享元模式(FlyWeight):

概念:

          将完全相同或者相似的对象,通过享元模式共享,节省内存空间。

核心:

  •    以共享的方式高效的支持大量细粒度对象的重用。享元对象能做到共享的关键是区分了内部状态和外部状态。
  •    内部状态:对象的内部属性,数据,占用空间大小都相同。
  •     外部状态:对象在内存空间中的地址不同。

核心组件:

  •     FlyWeightFactory享元工厂类: 创建并管理享元对象,享元池一般设计成键值对。
  •     FlyWeight抽象享元类:  通常是接口或者抽象类,声明公共方法,这些方法向外界提供对象的内部状态,设置外部状态。
  •     ConcreateFlyWeight具体享元类:为内部状态提供成员变量进行存储。
  •     UnsharedConcreateFlyWeight非共享享元类:不能被共享的子类可以设计为非共享享元类。

应用场景:

  •       由于享元模式共享的特征,常用在线程池,数据库连接池等...
  •       String类的设计也是享元模式。

优缺点:

  •       优点:减少内存中对象数量,相同或相似对象内存中只存一份,提高性能,外部状态相对独立不影响内部状态。
  •       缺点:模式较复杂,由于分离出 内部 外部状态,造成读取外部状态使运行时间变长。

举例实现:

1、
/**
 * 享元类
 */
public interface ChessFlyWeight {
    void setColor(String color);
    String getColor();
    void display(Coordinate c);

}

class ConcreteChess implements ChessFlyWeight {
    private String color;
    public ConcreteChess(String color) {
        this.color = color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public String getColor() {
        return color;
    }

    public void display(Coordinate c) {
        System.out.println("颜色:" + color);
        System.out.println("棋子位置:" + c.getX() + "-----" + c.getY());
    }
}


2、
/**
 * 外部状态UnsharedConcreateFlyWeight
 */
public class Coordinate {
    private int x,y;

    public Coordinate(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
}

3、
/**
 * 享元工厂类
 */
public class ChessFlyWeightFactory {
    private static Map<String , ChessFlyWeight> map = new HashMap<String , ChessFlyWeight>();

   public static ChessFlyWeight getChess(String color){
       if (map.get(color)!= null){
           return map.get(color);
       }else{
           ChessFlyWeight cfw = new ConcreteChess(color);
           map.put(color , cfw);
           return cfw;
       }
   }

   public static void main(String[] args){
       ChessFlyWeight chess1 = ChessFlyWeightFactory.getChess("黑色");
       ChessFlyWeight chess2 = ChessFlyWeightFactory.getChess("黑色");
       System.out.println(chess1);
       System.out.println(chess2);

       System.out.println("增加外部状态处理(自定义棋子位置)=====");
       chess1.display(new Coordinate(10,10));
       chess2.display(new Coordinate(20,20));
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值