行为型模式:
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己.
观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意数目的依赖它的Observer,一旦Subject的状态发生了变化,所有的Observer都可以得到通知。
Subject发出通知时并不需要知道谁是它的观察者,也就是说,具体观察者是谁,它根本不需要知道。而任何一个具体观察者不知道也不需要知道其他观察者的存在。
应用:
1,当一个对象的改变需要同时改变其他对象的时候,而且它不知道具体有多少对象有待改变时。
2,一个抽象模型有两个方面,其中一方面依赖于另一方面。观察者模式所做的工作就是在解耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
课本实例:前台帮同事观察老板的情况
代码如下:
//通知者接口 //一般用一个抽象类或者一个接口实现.它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者.抽象主题提供一个接口,可以增加和删除观察者对象 interface subject { void attach(Observer observer); void detch(Observer observer); void notify(); string subjectstate { get; set; } } //将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知 class boss : subject { //同事列表 private IList <Observer>observers=new List <Observer>(); private string action; //增加 public void attach(Observer observer) { observers.Add(observer); } //减少 public void detach(Observer observer) { observers.Remove(observer); } //通知 public void Notify() { foreach (Observer o in observers) o.update(); } //老板状态 public string subjectstate { get {return action;} set {action=value;} } } //抽象观察者 //为所有观察者定义一个接口,在得到主题通知时更新自己. abstract class Observer { protected string name; protected subject sub; public Observer(string name, subject sub) { this.name = name; this.sub = sub; } public abstract void update(); } //看股票的同事 //实现抽象观察者角色所要求的更新接口 class stockobserver : Observer { public stockobserver(string name, subject sub) : base(name, sub) { } public override void update() { Console.WriteLine("{0}{1}关闭股票行情,继续工作", sub.subjectstate, name); } }
个人理解观察者模式不足:
对于已经封装好的类来说,即使他们对某一变化产生动作,但产生这一动作的方法名称也不一定一样,如果我用观察者模式的话,当我定义抽象观察者时,是很麻烦的,需要改动已经封装好的类的名称等内容。
处理不足的措施:
委托- 一个委托可以搭载多个方法,所有方法被依次唤起,重要的是它可以使得委托对象所搭载的方法并不需要属于同一个类。委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型。
实现:去掉了父类“抽象观察类”并将“更新”方法名改为各自适合的方法名
模板方法模式
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
代码如下:
class testpaper { public void TestQuestion1() { Console.WriteLine("杨过得到,后来给了郭靖,练成倚天剑,屠龙刀的玄铁可能是()a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维"); Console.WriteLine("答案:" + answer1()); } protected virtual string answer1() { return " "; } } //学生甲抄的试卷 class testpaperA : testpaper { protected override string answer1() { return "b"; } } //学生乙抄的试卷 class testpaperB : testpaper { protected override string answer1() { return "c"; } }
命令模式
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
优点:
1,能较容易地设计一个命令队列
2,在需要的情况下,可以较容易地将命令记入日志
3,允许接收请求的一方决定是否要否决请求
4,可以容易地实现对请求的撤销和重做
5,鱼鱼加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易
6,命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开
课本实例:吃烤肉串
如图:
具体代码如下:
参见:http://baike.baidu.com/view/1854779.htm
http://blog.csdn.net/huangkangying/article/details/7901602
实现观察者模式的过程
实现观察者模式有很多形式,比较直观的一种是使用一种“注册——通知——撤销注册”的形式。下面的三个图详细的描述了这样一种过程:
1、观察者 (Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。
2、被观察对象 被观察对象发生了某种变化(如图中的SomeChange),从容器中得到所有注册过的观察者,将变化通知观察者。
3、撤销观察 观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。
class Observer(object):
"""
观察者类
"""
def __init__(self,subject):
#设定一个主题
self.subject = subject
#向这个主题添加这个观察者
self.subject.addObserver(self)
#观察者持有数据
self.fansnum = self.subject.fansnum
def update(self,fansnum):
self.fansnum = fansnum
self.display()
def display(self):
print self.fansnum
class Subject(object):
"""
主题类
"""
def __init__(self):
#观察者列表
self.observerList = []
self.fansnum = 0
#增加观察者
def addObserver(self,observer):
self.observerList.append(observer)
#删除观察者
def deleteObserver(self,observer):
if observer in self.observerList:
self.observerList.remove(observer)
其实带刻度的蜘蛛图网上也有不少资料,我这个也是参照别人的资料来做的,不管咋样,还是记上吧。
先上图
1、构造dataset
private DefaultCategoryDataset createDataSet2(Map<String, Map<String, Object>> resultMap, List<String> dimNameList) { DefaultCategoryDataset dataset = new DefaultCategoryDataset();//创建默认的种类数据类型就可以了,蜘蛛图的每个维度可以看成一种类型 Set<String> keySet = resultMap.keySet(); for(String key : keySet){ Map<String,Object> infoMap = resultMap.get(key); String vendorCode = key.split("&")[0]; String vendorName = key.split("&")[1]; for(String dimName : dimNameList){ if(infoMap.get(dimName)==null){ continue; } double score = (Double) infoMap.get(dimName); dataset.addValue(score, vendorName.trim() +"("+vendorCode.trim()+")", dimName); } } return dataset; }
2、因为jfreechart默认的蜘蛛图内容区域对象是不带刻度的,所以我们扩展一个好了,写一个扩展类继承SpiderWebPlot,主要是重写drawLabel方法,这个网上很多地方都有。
public class SpiderWebPlotExpand extends SpiderWebPlot{ private static final long serialVersionUID = 4005814203754627127L; private int ticks = DEFAULT_TICKS; private static final int DEFAULT_TICKS = 5; private NumberFormat format = NumberFormat.getInstance(); private static final double PERPENDICULAR = 90; private static final double TICK_SCALE = 0.015; private int valueLabelGap = DEFAULT_GAP; private static final int DEFAULT_GAP = 10; private static final double THRESHOLD = 15; public SpiderWebPlotExpand(CategoryDataset createCategoryDataset) { super(createCategoryDataset); } @Override protected void drawLabel(final Graphics2D g2, final Rectangle2D plotArea, final double value, final int cat, final double startAngle, final double extent) { super.drawLabel(g2, plotArea, value, cat, startAngle, extent); final FontRenderContext frc = g2.getFontRenderContext(); final double[] transformed = new double[2]; final double[] transformer = new double[2]; final Arc2D arc1 = new Arc2D.Double(plotArea, startAngle, 0, Arc2D.OPEN); for (int i = 1; i <= ticks; i++) { final Point2D point1 = arc1.getEndPoint(); final double deltaX = plotArea.getCenterX(); final double deltaY = plotArea.getCenterY(); double labelX = point1.getX() - deltaX; double labelY = point1.getY() - deltaY; final double scale = ((double) i / (double) ticks); final AffineTransform tx = AffineTransform.getScaleInstance(scale, scale); final AffineTransform pointTrans = AffineTransform.getScaleInstance(scale + TICK_SCALE, scale + TICK_SCALE); transformer[0] = labelX; transformer[1] = labelY; pointTrans.transform(transformer, 0, transformed, 0, 1); final double pointX = transformed[0] + deltaX; final double pointY = transformed[1] + deltaY; tx.transform(transformer, 0, transformed, 0, 1); labelX = transformed[0] + deltaX; labelY = transformed[1] + deltaY; double rotated = (PERPENDICULAR); AffineTransform rotateTrans = AffineTransform.getRotateInstance(Math.toRadians(rotated), labelX, labelY); transformer[0] = pointX; transformer[1] = pointY; rotateTrans.transform(transformer, 0, transformed, 0, 1); final double x1 = transformed[0]; final double y1 = transformed[1]; rotated = (-PERPENDICULAR); rotateTrans = AffineTransform.getRotateInstance(Math.toRadians(rotated), labelX, labelY); rotateTrans.transform(transformer, 0, transformed, 0, 1); final Composite saveComposite = g2.getComposite(); g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); g2.draw(new Line2D.Double(transformed[0], transformed[1], x1, y1)); if (startAngle == this.getStartAngle()) { final String label = format.format(((double) i / (double) ticks) * this.getMaxValue()); final LineMetrics lm = getLabelFont().getLineMetrics(label, frc); final double ascent = lm.getAscent(); if (Math.abs(labelX - plotArea.getCenterX()) < THRESHOLD) { labelX += valueLabelGap; labelY += ascent / (float) 2; } else if (Math.abs(labelY - plotArea.getCenterY()) < THRESHOLD) { labelY += valueLabelGap; } else if (labelX >= plotArea.getCenterX()) { if (labelY < plotArea.getCenterY()) { labelX += valueLabelGap; labelY += valueLabelGap; } else { labelX -= valueLabelGap; labelY += valueLabelGap; } } else { if (labelY > plotArea.getCenterY()) { labelX -= valueLabelGap; labelY -= valueLabelGap; } else { labelX += valueLabelGap; labelY -= valueLabelGap; } } g2.setPaint(getLabelPaint()); g2.setFont(getLabelFont()); g2.drawString(label, (float) labelX, (float) labelY); } g2.setComposite(saveComposite); } } }
3、创建chart
private JFreeChart createChart2(DefaultCategoryDataset dataSet) { SpiderWebPlotExpand plot = new SpiderWebPlotExpand(dataSet); JFreeChart chart = new JFreeChart("维度得分分析", plot); return chart; }
这次就比较简单了,因为网上例子不少,记在这里只是给自己以后查找方便,哈
已有 0 人发表留言,猛击->>这里<<-参与讨论
ITeye推荐
- —软件人才免语言低担保 赴美带薪读研!—