📄 sect14.htm
字号:
you want to create. In addition, if the prototyping fails, the
<B>factory( )</B> method will assume that it’s because a particular
<B>Class</B> object wasn’t in the list, and it will attempt to load it. By
loading the prototypes dynamically like this, the <B>Trash</B> class
doesn’t need to know what types it is working with, so it doesn’t
need any modifications when you add new types. This allows it to be easily
reused throughout the rest of the chapter.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_362">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE># c12:trash:Trash.py
# Base <font color=#0000ff>class</font> <font color=#0000ff>for</font> Trash recycling examples.
<font color=#0000ff>class</font> Trash:
private double weight
<font color=#0000ff>def</font> __init__(self, double wt): weight = wt
<font color=#0000ff>def</font> __init__(self):
<font color=#0000ff>def</font> getValue(self)
<font color=#0000ff>def</font> getWeight(self): <font color=#0000ff>return</font> weight
# Sums the value of Trash given an
# Iterator to any container of Trash:
<font color=#0000ff>def</font> sumValue(self, Iterator it):
double val = 0.0f
<font color=#0000ff>while</font>(it.hasNext()):
# One kind of RTTI:
# A dynamically-checked cast
Trash t = (Trash)it.next()
val += t.getWeight() * t.getValue()
<font color=#0000ff>print</font> (
<font color=#004488>"weight of "</font> +
# Using RTTI to get type
# information about the <font color=#0000ff>class</font>:
t.getClass().getName() +
<font color=#004488>" = "</font> + t.getWeight())
<font color=#0000ff>print</font> <font color=#004488>"Total value = "</font> + val
# Remainder of <font color=#0000ff>class</font> provides
# support <font color=#0000ff>for</font> prototyping:
private static List trashTypes =
ArrayList()
<font color=#0000ff>def</font> factory(self, Messenger info):
<font color=#0000ff>for</font>(int i = 0 i < len(trashTypes) i++):
# Somehow determine the type
# to create, <font color=#0000ff>and</font> create one:
Class tc = (Class)trashTypes.get(i)
<font color=#0000ff>if</font> (tc.getName().index(info.id) != -1):
<font color=#0000ff>try</font>:
# Get the dynamic constructor method
# that takes a double argument:
Constructor ctor = tc.getConstructor(
Class[]{ double.<font color=#0000ff>class</font> )
# Call the constructor
# to create a object:
<font color=#0000ff>return</font> (Trash)ctor.newInstance(
Object[]{Double(info.data))
catch(Exception ex):
ex.printStackTrace(System.err)
throw RuntimeException(
<font color=#004488>"Cannot Create Trash"</font>)
# Class was <font color=#0000ff>not</font> <font color=#0000ff>in</font> the list. Try to load it,
# but it must be <font color=#0000ff>in</font> your <font color=#0000ff>class</font> path!
<font color=#0000ff>try</font>:
<font color=#0000ff>print</font> <font color=#004488>"Loading "</font> + info.id
trashTypes.add(Class.forName(info.id))
catch(Exception e):
e.printStackTrace(System.err)
throw RuntimeException(
<font color=#004488>"Prototype not found"</font>)
# Loaded successfully.
# Recursive call should work:
<font color=#0000ff>return</font> factory(info)
public static <font color=#0000ff>class</font> Messenger:
public String id
public double data
public Messenger(String name, double val):
id = name
data = val
# :~</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The basic <B>Trash</B> class
and <B>sumValue( )</B> remain as before. The rest of the class supports the
prototyping pattern. You first see two
<A NAME="Index54"></A><A NAME="Index55"></A>inner classes (which are made
<B>static</B>, so they are inner classes only for code organization purposes)
describing exceptions that can occur. This is followed by an <B>ArrayList
</B>called <B>trashTypes</B>, which is used to hold the <B>Class</B> references.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_363">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>Trash.factory( )</B>, the
<B>String</B> inside the <B>Messenger </B>object <B>id </B>(a different version
of the <B>Messenger</B> class than that of the prior discussion) contains the
type name of the <B>Trash </B>to be created; this <B>String</B> is compared to
the <B>Class</B> names in the list. If there’s a match, then that’s
the object to create. Of course, there are many ways to determine what object
you want to make. This one is used so that information read in from a file can
be turned into objects.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_364">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Once you’ve discovered which kind
of <B>Trash</B> to create, then the <A NAME="Index56"></A>reflection methods
come into play. The <A NAME="Index57"></A><B>getConstructor( )</B> method
takes an argument that’s an array of <A NAME="Index58"></A><B>Class</B>
references. This array represents the arguments, in their proper order, for the
constructor that you’re looking for. Here, the
<A NAME="Index59"></A><A NAME="Index60"></A>array is dynamically created using
the Java 1.1<A NAME="Index61"></A> array-creation syntax:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_365">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Class[]:double.<font color=#0000ff>class</font></PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This code
assumes that every <B>Trash</B> type has a constructor that takes a <B>double
</B>(and notice that <B>double.class</B> is distinct from <B>Double.class</B>).
It’s also possible, for a more flexible solution, to call
<A NAME="Index62"></A><B>getConstructors( )</B>, which returns an array of
the possible constructors.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_366">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">What comes back from
<B>getConstructor( ) </B>is a reference to a
<A NAME="Index63"></A><B>Constructor</B> object (part of
<B>java.lang.reflect</B>). You call the constructor dynamically with the method
<A NAME="Index64"></A><B>newInstance( )</B>, which takes an array of
<B>Object</B> containing the actual arguments. This array is again created using
the Java 1.1<A NAME="Index65"></A> syntax:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_367">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Object[]{Double(Messenger.data)</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In
this case, however, the <B>double</B> must be placed inside a wrapper class so
that it can be part of this array of objects. The process of calling
<B>newInstance( )</B> extracts the <B>double</B>, but you can see it is a
bit confusing—an argument might be a <B>double </B>or a <B>Double</B>, but
when you make the call you must always pass in a <B>Double</B>. Fortunately,
this issue exists only for the primitive types.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_368">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Once you understand how to do it, the
process of creating a new object given only a <B>Class</B> reference is
remarkably simple. Reflection also allows you to call methods in this same
dynamic fashion.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_369">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course, the appropriate <B>Class</B>
reference might not be in the <B>trashTypes</B> list. In this case, the
<B>return</B> in the inner loop is never executed and you’ll drop out at
the end. Here, the program tries to rectify the situation by loading the
<B>Class</B> object dynamically and adding it to the <B>trashTypes</B> list. If
it still can’t be found something is really wrong, but if the load is
successful then the <B>factory</B> method is called
<A NAME="Index66"></A><A NAME="Index67"></A>recursively to try again.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_370">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As you’ll see, the beauty of this
design is that this code doesn’t need to be changed, regardless of the
different situations it will be used in (assuming that all <B>Trash</B>
subclasses contain a constructor that takes a single <B>double</B> argument).
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_371">Add Comment</A></FONT><A NAME="_Toc534420136"></A><BR></P></DIV>
<A NAME="Heading87"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Trash subclasses</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To fit into the prototyping scheme, the
only thing that’s required of each new subclass of <B>Trash</B> is that it
contain a constructor that takes a <B>double</B> argument. Java reflection
handles everything else.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_372">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here are the different types of
<B>Trash</B>, each in their own file but part of the <B>Trash</B> package
(again, to facilitate reuse within the chapter):
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_373">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE># c12:trash:Aluminum.py
# The Aluminum <font color=#0000ff>class</font> with prototyping.
<font color=#0000ff>class</font> Aluminum(Trash):
private static double val = 1.67f
<font color=#0000ff>def</font> __init__(self, double wt): .__init__(wt)
<font color=#0000ff>def</font> getValue(self): <font color=#0000ff>return</font> val
<font color=#0000ff>def</font> setValue(self, double newVal):
val = newVal
# :~</PRE></FONT></BLOCKQUOTE>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE># c12:trash:Paper.py
# The Paper <font color=#0000ff>class</font> with prototyping.
<font color=#0000ff>class</font> Paper(Trash):
private static double val = 0.10f
<font color=#0000ff>def</font> __init__(self, double wt): .__init__(wt)
<font color=#0000ff>def</font> getValue(self): <font color=#0000ff>return</font> val
<font color=#0000ff>def</font> setValue(self, double newVal):
val = newVal
# :~</PRE></FONT></BLOCKQUOTE>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE># c12:trash:Glass.py
# The Glass <font color=#0000ff>class</font> with prototyping.
<font color=#0000ff>class</font> Glass(Trash):
private static double val = 0.23f
<font color=#0000ff>def</font> __init__(self, double wt): .__init__(wt)
<font color=#0000ff>def</font> getValue(self): <font color=#0000ff>return</font> val
<font color=#0000ff>def</font> setValue(self, double newVal):
val = newVal
# :~</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">And here’s a new type of
<B>Trash</B>:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_374">Add Comment</A></FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE># c12:trash:Cardboard.py
# The Cardboard <font color=#0000ff>class</font> with prototyping.
<font color=#0000ff>class</font> Cardboard(Trash):
private static double val = 0.23f
<font color=#0000ff>def</font> __init__(self, double wt): .__init__(wt)
<font color=#0000ff>def</font> getValue(self): <font color=#0000ff>return</font> val
<font color=#0000ff>def</font> setValue(self, double newVal):
val = newVal
# :~</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that, other than
the constructor, there’s nothing special about any of these classes.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_375">Add Comment</A></FONT><A NAME="_Toc534420137"></A><BR></P></DIV>
<A NAME="Heading88"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Parsing Trash from an external file</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The information about <B>Trash</B>
objects will be read from an outside file. The file has all of the necessary
information about each piece of trash on a single line in the form
<B>Trash:weight</B>, such as:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_376">Add Comment</A></FONT><BR></P></DIV>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -