设计模式之结构性模式(二)

设计模式之结构性模式(二)

三、桥接模式

四、组合模式

五、装饰模式

三、桥接模式

如果用多层继承结构实现下图关系,有如下问题:
1)扩展性问题
2)违反单一职责原则
在这里插入图片描述
将其分为两个维度:
类型维度和品牌维度
在这里插入图片描述

Computer2

/**
 * 电脑类型
 */
package com.bridge;

public class Computer2 {

    //品牌
    protected Brand brand;
    
    public Computer2(Brand brand) {
    	this.brand = brand;
    }
    
    public void sale() {
    	brand.sale();
    }
}

//台式机
class Desktop2 extends Computer2 {

    public Desktop2(Brand brand) {
    super(brand);
    }
    
    public void sale() {
	    super.sale();
	    System.out.println("销售台式机");
	    }
    }
    
    //笔记本
    class Laptop2 extends Computer2 {
    
    public Laptop2(Brand brand) {
   		super(brand);
    }
    
    public void sale() {
	    super.sale();
	    System.out.println("销售笔记本");
    }
}

//平板
class Pad2 extends Computer2 {

public Pad2(Brand brand) {
	super(brand);
}

public void sale() {
    super.sale();
    System.out.println("销售平板");
    }
}

Brand

/**
 * 品牌类型
 */
package com.bridge;

public interface Brand {
	public void sale();
}

class Lenovo implements Brand {

@Override
public void sale() {
    System.out.println("销售联想电脑");
    }
}

class Dell implements Brand {

@Override
public void sale() {
    System.out.println("销售戴尔电脑");
    }
}

Client

package com.bridge;

public class Client {
public static void main(String[] args) {
    Computer2 c = new Desktop2(new Lenovo());
    c.sale();
    }
}

结果:

销售联想电脑
销售台式机

桥接模式总结:

1)可以取代多层继承方案,多层继承违背了单一职责原则,复用性差,类个数多;桥接模式极大减少了子类的个数,降低管理和维护成本
2)桥接模式提高了系统的可扩展性,在两个变化的维度中任意变化一个维度,都不需要修改原有的系统,符合开闭原则

桥接模式应用场景:

扫描二维码关注公众号,回复: 4046233 查看本文章

1)JDBC驱动程序
2)AWT中的Peer架构
3)银行日志管理
格式分类:操作日志、交易日志、异常日志
距离分类:本地记录日志、异地记录日志
4)人力资源系统中的奖金奖金计算模块
5)OA系统中的消息处理

四、组合模式

使用场景:把部分和整体的关系用树形结构来表示,从而使客户端可以使用统一的方式处理部分对象和整体对象

核心:
抽象挂件(Component)角色:定义了叶子和容器构建的共同点
叶子(Leaf)构件角色:无子节点
容器(Composite)构件角色:有容器特征,可以包含叶子节点

组合模式工作流程分析:
1)组合模式为处理树形结构提供了完美的解决方案,描述如何将容器和叶子进行递归组合,使得用户在使用时可以一致性的对待容器和叶子。
2)当容器对象的指定方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员,并执行调用,其中,使用了递归调用的机制对整个结构进行处理

实例:模拟杀毒软件架构设计

Conponent

/**
 * 抽象组件
 */
package com.composite;

public interface Component {
	public void operation();
}

//叶子组件
interface Leaf extends Component {

}

//容器组件
interface Composite extends Component {
    void add(Component c);
    void remove(Component c);
    Composite getChild(int index);
}

AbstractFile

package com.composite;

import java.util.ArrayList;
import java.util.List;

//抽象构建
public interface AbstractFile {
	void killVirus();//查毒
}

//文本文件
class TextFile implements AbstractFile {

	    private String name;
	    
	    public TextFile(String name) {
	    this.name = name;
    }
    
    @Override
    public void killVirus() {
  		  System.out.println("---文本文件:"+this.name+",进行查杀");
    }
}

//图像文件
class ImageFile implements AbstractFile {
    
    private String name;
    
    public ImageFile(String name) {
    	this.name = name;
    }
    
    @Override
    public void killVirus() {
   		 System.out.println("---图像文件:"+this.name+",进行查杀");
    }
}

//视频文件
class VedioFile implements AbstractFile {

    private String name;
    
    public VedioFile(String name) {
   		this.name = name;
    }
    
    @Override
    public void killVirus() {
    	System.out.println("---视频文件:"+this.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 AbstractFile getChild(int index) {
   		return list.get(index);
    }
    
    @Override
    public void killVirus() {
   		System.out.println("---文件夹:"+this.name+",进行查杀");
    
    //遍历容器
    for(AbstractFile file:list) {
	    file.killVirus();
	    }
    }
}

Client

package com.composite;

public class Client {
    public static void main(String[] args) {

    AbstractFile f1,f2,f3;//文件
    Folder f = new Folder("我的收藏");//文件夹
    Folder f11 = new Folder("我的电影");//文件夹
    
	//文件
    f1 = new TextFile("hello.txt");
    f2 = new ImageFile("111.jpg");
    f3 = new VedioFile("视频");

    //将各个文件加入到文件夹中
    f.add(f1);
    f.add(f2);
    
    f11.add(f3);
    f.add(f11);
    
    //查杀文件夹
    f.killVirus();
    }
}

结果

---文件夹:我的收藏,进行查杀
---文本文件:hello.txt,进行查杀
---图像文件:111.jpg,进行查杀
---文件夹:我的电影,进行查杀
---视频文件:视频,进行查杀

组合模

式应用场景:
1)操作系统的资源管理器
2)GUI中的容器层次图
2)XML文件解析
4)OA系统中组织结构的处理
5)Junit单元测试框架
底层设计就是典型的组合模式,TestCase(叶子)、TestUnite(容器)、Test接口(抽象)

五、装饰模式

职责:
1)动态的为一个对象增加新的功能
2)装饰模式是一种代替继承的技术,无需通过继承增加子类就能扩展性功能,使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀

实现细节:

1)Component抽象构件角色
真实对象和装饰对象有相同的接口,因此客户端对象能够以与真实对象相同的方式同装饰对象交互
2)ConcreteComponent具体构件角色(真实对象)
io流中的FileInputStream、FileOutputStream
3)Decorator装饰角色
持有一个抽象构件的引用,装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象,因此就能在真是对象调用后增加新的功能
4)ConcreteDecorato具体装饰角色
负责给构件对象增加新的责任

实例:车

实现细节:

package com.decorate;

//抽象构件角色Component
public interface Icar {
	public void move();
}

//具体构件角色ConcreteComponent
class Car implements Icar {
    @Override
    public void move() {
    	System.out.println("陆地上跑");
    }
}

//Decorate装饰角色
class SuperCar implements Icar {
    //protected供子类使用
    protected Icar car;
    
    public SuperCar(Icar car) {
	    super();
	    this.car = car;
    }
    
    @Override
    public void move() {
   		car.move();
    }
}

//具体装饰角色ConcreteDecorate
class FlyCar extends SuperCar {

    public FlyCar(Icar car) {
    	super(car);
    }
    
    public void fly() {
    	System.out.println("天上飞");
    }
    
    @Override
    public void move() {
	    super.move();
	    fly();
    }
}

class WaterCar extends SuperCar {

    public WaterCar(Icar car) {
    	super(car);
    }
    
    public void swim() {
    System.out.println("水上游");
    }
    
    @Override
    public void move() {
	    super.move();
	    swim();
    }
}

class AICar extends SuperCar {

    public AICar(Icar car) {
    	super(car);
    }
    
    public void autoRun() {
    	System.out.println("自动跑");
    }
    
    @Override
    public void move() {
	    super.move();
	    autoRun();
    }
}

Client

package com.decorate;

public class Client {
    public static void main(String[] args) {
	    Car car = new Car();
	    car.move();
	    
	    System.out.println("------增加新的功能:天上飞------");
	    FlyCar flyCar = new FlyCar(car);
	    flyCar.move();
	    
	    System.out.println("------增加新的功能:水上游------");
	    WaterCar waterCar = new WaterCar(car);
	    waterCar.move();
	    
	    System.out.println("------增加两个新的功能:自动天上飞------");
	    AICar aiCar = new AICar(new FlyCar(car));
	    aiCar.move();
    
    }
}

结果

陆地上跑
------增加新的功能:天上飞------
陆地上跑
天上飞
------增加新的功能:水上游------
陆地上跑
水上游
------增加两个新的功能:自动天上飞------
陆地上跑
天上飞
自动跑

IO流实现细节:
1)Conponent抽象构件角色
io流中InputStream、OutputStream、Reader、Writer
2)ConcreteComponent具体构件角色
io流中FileInputStream、FileOutputStream
3)DEcorator装饰角色
持有一个抽象构件的引用:io流中的FilterInoutStream、FilterOutputStream
4)ConcreteDecorator具体装饰角色
负责给构件对象增加新的责任,io流中的BufferdInputStream、BufferedOutputStream

开发中使用场景:
1)io输入流和输出流的设计
2)Swing包中图形界面构建功能
3)Servlet API中提供一个request对象的Decorator设计模式的默认实现类HttpServletrequestWrapper,增强request对象功能

总结:装饰模式也叫包装器模式;装饰模式降低系统的耦合度,可以动态的增加或删除对象职责,并使得需要装饰的具体构件类和具体装饰类可以独立变化,一边则更加新的具体构件类和具体装饰类

优点:
1)扩展对对象功能,比继承灵活,不会导致类个数急剧增加
2)可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象
3)具体构件类和具体装饰类可以独立变化,,用户可以根据自己需要增加新的具体构件子类和具体装饰子类

缺点:
1)产生很多小对象,大量小对象占据内存,一定程度上影响性能
2)装饰模式易于出错,调试排查比较麻烦

装饰模式和桥接模式的区别:
都是为了解决过多子类对象问题,桥接模式是对象自身现有机制沿着多个维度变化,有部分不稳定;装饰模式是为了增加新的功能

猜你喜欢

转载自blog.csdn.net/mys_mys/article/details/83892761
今日推荐