设计模式之合成模式

如有转载,请申明:

转载至 http://blog.csdn.net/qq_35064774/article/details/52080149


1 什么是合成模式

 

合成模式属于对象的结构模式。合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式可以使客户端将单纯元素与复合元素同等看待。

 

这定义看着太抽象了,我们举个栗子。

在二维图形中,线、圆、矩形等都可以看作是图形,而通过简单图形组合起来的图形也可以看作图形。

 

 

2 如何实现合成模式

 

合成模式可分为安全式和透明式。

 

简单说来就是,透明式是对树枝树叶类提供相同的接口,树叶类也有管理聚合的方法。安全式则是只有树枝类有管理聚合的方法。

 

这里简单解释一下树枝和树叶类。就拿上面举的例子,线、圆、矩形这些简单图形看作是树叶类,也就是不是由对象组合而成的对象。而复杂的组合图形就是树枝类。

 

为了方便书写代码,我们引入一个问题。

 

 * 现有一个矢量图绘图程序

 * 支持画线、椭圆、矩形

 * 我们可以通过这三种图形组合出其他图形

 * 现在想把这个组合出来的图形当成一个新的图形

 

 

拿到这个问题,我们很容易就想到要用合成模式。

针对这个问题,我们大致需要定义抽象的图形类、线类、椭圆类、矩形类等。

 

首先定义抽象类。

 

package com.ittianyu.composite;

import java.awt.Graphics;

public interface Drawable {
	void draw(Graphics g);
}


 

这里定了为一个接口,所有图形都应该有一个方法draw,这个参数是awt中用来自定义绘图的对象,如果学过javaGUI的就会明白了,不明白也没关系,这里只是为了视觉效果才用的。

 

接下来我们定义简单的图像类。这些类主要是属性和draw方法有区别,所以这里不再过多解释。

 

package com.ittianyu.composite;

import java.awt.Graphics;

public class Line implements Drawable {
	private int x1, y1;
	private int x2, y2;
	
	public Line(int x1, int y1, int x2, int y2) {
		super();
		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
	}
	
	@Override
	public void draw(Graphics g) {
		g.drawLine(x1, y1, x2, y2);
	}
}


package com.ittianyu.composite;

import java.awt.Graphics;

public class Oval implements Drawable {
	private int x, y;
	private int width, height;
	
	public Oval(int x, int y, int width, int height) {
		super();
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}

	@Override
	public void draw(Graphics g) {
		g.drawOval(x, y, width, height);
	}
}


package com.ittianyu.composite;

import java.awt.Graphics;

public class Rectangle implements Drawable {
	private int x, y;
	private int width, height;
	
	public Rectangle(int x, int y, int width, int height) {
		super();
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}

	@Override
	public void draw(Graphics g) {
		g.drawRect(x, y, width, height);
	}
}


 

有了简单图形后,我们还需要一个类似于容器类的图形类,来作为组合图形。

 

package com.ittianyu.composite;

import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;

public class Graph implements Drawable {
	private List<Drawable> graphs = new ArrayList<Drawable>();
	
	@Override
	public void draw(Graphics g) {
		for(int i = 0; i < graphs.size(); i++)
			graphs.get(i).draw(g);
	}
	
	public Graph add(Drawable d) {
		graphs.add(d);
		return this;
	}
	
	public Graph remove(Drawable d) {
		graphs.remove(d);
		return this;
	}
	
	public Drawable get(int index) {
		return graphs.get(index);
	}
}


 

 

我们可以发现,这个容器类也实现了Drawable ,也就是可以被外界当作图形类。这是组合最关键的思想。

其次这个组合类提供了addremoveget等的聚合管理方法,我们就可以方便的把其他图形加入。

 

代码写到这里基本就实现了组合模式。最后还需要测试,由于我这里想直接在窗口里面绘制图形,所以还需要一个窗口类和测试类。

 

package com.ittianyu.composite;

import java.awt.Frame;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class DrawFrame extends Frame {
	private Drawable draw;
	
	public DrawFrame(String title) throws HeadlessException {
		super(title);
		this.setVisible(true);
		this.setSize(800, 600);
		// 响应关闭窗口事件
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				super.windowClosed(e);
				System.exit(0);
			}
		});
	}
	
	public Drawable getDraw() {
		return draw;
	}

	public void setDraw(Drawable draw) {
		this.draw = draw;
		this.repaint();
	}

	@Override
	public void paint(Graphics g) {
		if(null == draw)
			return;
		
		draw.draw(g);
	}
}


 

定义这个窗口类,里面可以设置Drawable 对象,并在paint中调用。

最后一步,写一个测试类。

 

package com.ittianyu.composite;

public class Test {
	public static void main(String[] args) {
		Graph graph = new Graph();
		graph.add(new Line(0, 0, 800, 600))
			.add(new Oval(100, 100, 200, 150))
			.add(new Rectangle(400, 300, 300, 200));
		
		DrawFrame frame = new DrawFrame("绘图测试");
		frame.setDraw(graph);
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		frame.setDraw(new Oval(200, 150, 400, 300));
	}
}


 

可以发现,在窗口中,我们既可以绘制简单图形,也可以绘制组合图形。

 

3 在什么情况下使用合成模式

 

 * 在把对象和由对象组合而成的复杂对象都看作同一类对象时,使用合成模式比较合适。

 

 

4 合成模式的优点和缺点

 

优点:

 * 增加新种类构建变得轻松

 * 使用时不需要知道当前使用的是树枝接点还是树叶接点,也就是不需要知道对象是不是组合而成的。

 

缺点:

 * 控制树枝构建的类型不太容易。

 * 继承的方式完成新功能的增加变得困难。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值