⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mondrian.html

📁 Concurrent Programming in Java
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<html><!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><html> <head><title>Mondrian Factory Example</title></head><BODY bgcolor=#ffffee vlink=#0000aa link=#cc0000><h1><a name="secMondrian"></a>Mondrian Factory Example</h1><p> This is a <a href="activityFlow.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/activityFlow.html">push-driven</a> assemblyline that builds series of ``Mondrian'' paintings that can, amongother possibilities look like the ones displayed by the followingApplet (assuming you are running a browser that can show Applets): <p><applet  codebase="tppjava" tppabs="http://g.oswego.edu/dl/classes/"  code="aop.AssemblyLine.class" tppabs="http://g.oswego.edu/dl/classes/aop.AssemblyLine.class"  width=201  height=201></applet><p><blockquote> Footnote: <ahref="javascript:if(confirm('http://watt.emf.net/wm/paint/auth/mondrian/  \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address.  \n\nDo you want to open it from the server?'))window.location='http://watt.emf.net/wm/paint/auth/mondrian/'" tppabs="http://watt.emf.net/wm/paint/auth/mondrian/">Piet Mondrian </a>was an artist who produced many paintings consisting of colored boxes(rectangles) arranged and embedded in various non-overlappingways. Pseudo-Mondrian construction is a favorite activity among someprogrammers and example code writers. See for example, the onesin <a href="javascript:if(confirm('http://sunsite.unc.edu/javafaq/javatutorial.html  \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address.  \n\nDo you want to open it from the server?'))window.location='http://sunsite.unc.edu/javafaq/javatutorial.html'" tppabs="http://sunsite.unc.edu/javafaq/javatutorial.html">Elliotte Rusty Harold's Java Tutorial</a>.<p>But actually, thisApplet produces things that look more like Mark Rothko paintings.</blockquote><p><blockquote> Note: All source code described in this example can beobtained as the single file <ahref="javascript:if(confirm('http://g.oswego.edu/dl/classes/aop/AssemblyLine.java  \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address.  \n\nDo you want to open it from the server?'))window.location='http://g.oswego.edu/dl/classes/aop/AssemblyLine.java'" tppabs="http://g.oswego.edu/dl/classes/aop/AssemblyLine.java">AssemblyLine.java</a>.</blockquote><h2> Representations </h2>To start out, we need some base representation types. In this example,all of these can be made to be subclasses of abstract class<code>Box</code>, where every Box has a color, a size, can displayitself when asked, and can be made to (``deeply'') clone(<code>duplicate</code>) itself:<pre>public abstract class Box {   protected Color color_;  protected Box() { color_ = Color.white;  }  public synchronized Color color()         { return color_; }  public synchronized void  color(Color c)  { color_ = c; }  public abstract Box duplicate();  public abstract Point size();  public abstract void show(Graphics g, Point origin);}</pre><blockquote> Footnote. The java.awt.Point class is used to represent(width, height) pairs. This works OK but leads to someawkardnesses. It might have been simpler to just have separate widthand height methods.  </blockquote><p>The idea is of this assembly line is that we'll start off withsources that produce simple basic boxes, and then push them throughstages that paint, join, flip, and embed them to form ourpseudo-Mondrians. The basic boxes are the simplest possibleimplementation subclass:<pre>public class BasicBox extends Box {  protected Point size_;  public BasicBox(int xdim, int ydim) {    super();    size_ = new Point(xdim, ydim);  }  public synchronized Point size() { return size_; }  public void show(Graphics g, Point origin) {    g.setColor(color_);    g.fillRect(origin.x, origin.y, size().x, size().y);  }  public synchronized Box duplicate() {     Box p =  new BasicBox(size_.x, size_.y);    p.color(color_);    return p;  }}</pre>Two fancier kinds of boxes can be made by Joining side-by-side twoexisting boxes, adding a line-based border surrounding them. This canbe done in either of two ways, horizontally or vertically.  The tworesulting classes can be made subclasses of JoinedPair to allowsharing of some common code:<pre>public abstract class JoinedPair extends Box {  protected Box fst_;  protected Box snd_;  protected JoinedPair(Box fst, Box snd) {    super();    fst_ = fst;    snd_ = snd;  }  public synchronized void flip() {    Box tmp = fst_; fst_ = snd_; snd_ = tmp;  }  protected int maxX() {     Point fs = fst_.size(); Point ss = snd_.size();    return fs.x > ss.x ? fs.x : ss.x;  }  protected int maxY() {     Point fs = fst_.size(); Point ss = snd_.size();    return fs.y > ss.y ? fs.y : ss.y;  }  protected int sumX() {     Point fs = fst_.size(); Point ss = snd_.size();    return fs.x + ss.x;  }  protected int sumY() {     Point fs = fst_.size(); Point ss = snd_.size();    return fs.y + ss.y;  }}public class HorizontallyJoinedPair extends JoinedPair {  public HorizontallyJoinedPair(Box l, Box r) { super(l, r); }  public synchronized Point size() {  return new Point(sumX(), maxY()); }  public void show(Graphics g, Point origin) {    Point fstOffset = null;    Point sndOffset = null;    Point fs = fst_.size();    Point ss = snd_.size();    if (fs.y >= ss.y) {      fstOffset = origin;      sndOffset = new Point(origin.x + fs.x, origin.y + (fs.y - ss.y) / 2);    }    else {      fstOffset = new Point(origin.x,  origin.y + (ss.y - fs.y) / 2);      sndOffset = new Point(origin.x + fs.x, origin.y);    }    fst_.show(g, fstOffset);    snd_.show(g, sndOffset);    g.setColor(color_);    g.drawLine(origin.x + fs.x, origin.y, origin.x + fs.x, origin.y + fs.y);  }  public synchronized Box duplicate() {     HorizontallyJoinedPair p =       new HorizontallyJoinedPair(fst_.duplicate(), snd_.duplicate());    p.color(color_);    return p;  }}public class VerticallyJoinedPair extends JoinedPair {  public VerticallyJoinedPair(Box u, Box d) { super(u, d); }  public synchronized Point size() {  return new Point(maxX(), sumY()); }  public void show(Graphics g, Point origin) {    Point fstOffset = null;    Point sndOffset = null;    Point fs = fst_.size();    Point ss = snd_.size();    if (fs.x >= ss.x) {      fstOffset = origin;      sndOffset = new Point(origin.x + (fs.x - ss.x) / 2, origin.y + fs.y);    }    else {      fstOffset = new Point(origin.x + (ss.x - fs.x) / 2, origin.y);      sndOffset = new Point(origin.x, origin.y + fs.y);    }    fst_.show(g, fstOffset);    snd_.show(g, sndOffset);    g.setColor(color_);    g.drawLine(origin.x, origin.y + fs.y, origin.x + fs.x, origin.y + fs.y);  }  public synchronized Box duplicate() {     VerticallyJoinedPair p =       new VerticallyJoinedPair(fst_.duplicate(), snd_.duplicate());    p.color(color_);    return p;  }}</pre>Our final kind of fancy box wraps one Box within a border:<pre>public class WrappedBox extends Box {  protected Point wrapperSize_;  protected Box inner_;  public WrappedBox(Box inner, Point wrapperSize) {    inner_ = inner;    wrapperSize_ = wrapperSize;  }  public synchronized Point size() {     return new Point(inner_.size().x + wrapperSize_.x,                     inner_.size().y + wrapperSize_.y);  }    public void show(Graphics g, Point origin) {    g.setColor(color_);    g.fillRect(origin.x, origin.y, size().x, size().y);    inner_.show(g, new Point(origin.x + wrapperSize_.x / 2,                             origin.y + wrapperSize_.y / 2));  }  public synchronized Box duplicate() {     WrappedBox p = new WrappedBox(inner_.duplicate(), wrapperSize_);    p.color(color_);    return p;  }}</pre><h2>Stages</h2>We've set things up to support the following kinds of stages:<ul>  <li> BasicBoxSource: Create a new BasicBox.  <li> Painter: change the color of any kind of Box.  <li> Flipper: Flip (up-down or left-right) a JoinedPair.  <li> HorizontalJoiner: Combine two Boxes left-right, creating a new        composite.  <li> VerticalJoiner: Combine two Boxes up-down, creating a new        composite.  <li> Wrapper: Wrap a Box inside a border, creating a new composite.  <li> Cloner: Make a copy of a Box; pass the original to one        successor, and the clone to another.  <li> Alternator: Pass alternate inputs through to alternate successors.  <li> Screener: Pass some kinds of Boxes to one stage,       and others to another.  <li> Merger: Direct the results of two independent assembly lines to       a single successor.</ul><blockquote> Footnote: There's probably an algebra of Mondrians lurking here:-) </blockquote>Two of these kinds of stages (Painters and Flippers) simply change thestates of their sources using methods supported by the representedobjects themselves. Others accept zero (BasicBoxSource), one (Wrapper)or two (Joiners) incoming objects to create new kinds ofBoxes. Both Cloners and Alternators are kinds of Splitters. Mergers and related stages come into play as utilitiesto help with some of the basic ``plumbing''. <h3>Interfaces</h3><p> Looking ahead to how we might want to string these stagestogether, it is worthwhile to try to standardize on the interfaces.We'd like to be able to connect any stage to any other stage for whichit could make sense.  Since we are doing Push-based flow, theseinterfaces mainly describe <code>put</code>-style methods. In fact, wecould just call them all <code>put</code>, except that this doesn'twork very well for Combiner stages. For example, a VerticalJoinerneeds <em>two</em> <code>put</code> methods, one supplying the topBox, and one for the bottom Box. We could evade this by designingJoiners to take alternate incoming Boxes as the tops and bottoms, butthis would make them harder to control. Instead, we'll use thesomewhat ugly but easily extensible names <code>putA</code>,<code>putB</code>, and so on:<pre>public interface PushSource {  public void start();}public interface PushStage {  public void putA(Box p);}public interface DualInputPushStage extends PushStage {  public void putB(Box p);}</pre>We can make the ``B'' channels of DualInputPushStages completelytransparent to other stages by defining a simple Adaptor class thataccepts a <code>putA</code> but relays it to its indended recipients<code>putB</code>.  This way, most stages can be built to invoke<code>putA</code>, without knowing or caring that it is actually fedinto some successor's <code>B</code> channel:<pre>public class DualInputAdaptor implements PushStage {  protected DualInputPushStage stage_;  public DualInputAdaptor(DualInputPushStage stage) { stage_ = stage; }  public void putA(Box p) { stage_.putB(p); }}</pre>And, while we are focused on interfaces and adaptors, we can build asimple Runnable that helps to perform any <code>putA</code> in a Thread:<pre>public class PutARunner implements Runnable {  protected PushStage target_;  protected Box arg_;  public PutARunner(PushStage target, Box arg) {    target_ = target; arg_ = arg;   }  public void run() { target_.putA(arg_); }}</pre><h3>Connections</h3>The above interfaces standardize on the method names for stages, butdo nothing about the linkages to successors, which will be maintainedusing some kind of instance variables in each stage object.There are several options for doing this, including:<ol>  <li> Have each object maintain a collection object holding all       of its successors, as in typical <a href="early.html#secSubj" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/early.html#secSubj">       Subject/Observer</a> designs.  <li> Use a master connection registry, that each stage would know        about, and would interact with to find out its successor(s).  <li> Create the minimal possible representation:       Define a base class for stages that have exactly one successor       and one for those with exactly two successors. </ol>Option (3) is simplest and works fine here. (In fact it is always avalid option -- stages with three or more outputs can be built bycascading those for only two. Of course, you wouldn't want to do thisif most stages had large and/or variable numbers of successors.) Thisleads to base classes suppoprting either one or two links, and withone or two corresponding <code>attach</code> methods, using a similarugly suffix convention (attach1, attach2, ...):<pre>class SingleOutputPushStage {  protected PushStage next1_;  protected SingleOutputPushStage() { next1_ = null; }  public void attach1(PushStage s) { next1_ = s; }}class DualOutputPushStage extends SingleOutputPushStage {  protected PushStage next2_;  protected DualOutputPushStage() { super(); next2_ = null; }  public void attach2(PushStage s) { next2_ = s; }}</pre>Now we can build all sorts of classes that <code>extend</code> eitherof these base classes while simultaneously <code>implement</code>ing anyof the above kinds of <code>interfaces</code>.<h3>Linear Stages</h3>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -