抽象类WindowAdapter是变压器模式的一个例子 抽象类WindowAdapter是为接受视窗的事件而准备的此抽象类内所有的方法都是空的 使用此类可以很方便地创立listener对象置换(Override)你所感兴趣的那个事件所对应的方法 如果你不使用此抽象类那么你必然规律要实现WindowsListener接口而那样你就不得不实现所有接口中的方法 即便是你不需要的事件所对应的方法你也要给出一个空的方法而这显然不方便 显然抽象类WindowAdapter的目标接口可以选得与源接口一样而不影响效果 这就解释了为什么目标接口不出现在WindowAdapter类图(见下面)里 图 本例子SwingUI类与WindowAdapter实例变压器模式的类图定义 SwingUI类的代码如下 import javaawtColor; import javaawtBorderLayout; import javaawtevent*; import javaxswing*; class SwingUI extends JFrame implements ActionListener { JLabel text clicked; JButton button clickButton; JPanel panel; private boolean m_clickMeMode = true; Public SwingUI() { text = new JLabel(我很高兴!); button = new JButton(理我); buttonaddActionListener(this); panel = new JPanel(); panelsetLayout(new BorderLayout()); panelsetBackground(Colorwhite); getContentPane()add(panel); paneladd(BorderLayoutCENTER text); paneladd(BorderLayoutSOUTH button); } public void actionPerformed(ActionEvent event) { Object source = eventgetSource(); if (m_clickMeMode) { textsetText(我很烦!); buttonsetText(别理我); m_clickMeMode = false; } else { textsetText(我很高兴!); buttonsetText(理我); m_clickMeMode = true; } } public static void main(String[] args) { SwingUI frame = new SwingUI(); framesetTitle(我); WindowListener listener = new WindowAdapter() { public void windowClosing(WindowEvent e) { Systemexit(); } }; frameaddWindowListener(listener); framepack(); framesetVisible(true); } } 代码清单 SwingUI类的源代码红色的代码就是使用WindowAdapter的无名内部类 显然由于无名内部类是继承自WindowAdapter抽象类因此只需置换(override)掉我们需要的方法 即windowClosing()而不必操心WindowListener的其它方法 本例子在运行时的样子 图 SwingUI类在运行时的样子单击命令键理我就变成下图的样子 图 再单击命令键别理我就会回到前图的样子 利用变压器模式指方为圆 中国古代有赵高指鹿为马的故事鹿与马有很多相似之处没见过的人本就分辨不清指一指可能没什么大不了的 指方为圆是否太过?非也本例就是要指方为圆需要的只是变压器模式这个魔术手指(Magic Finger) 变压器模式在本例子的类图如下 图 指方为圆的变压器模式类图 package comjavapatternsadaptercubeball; public class Cube { public Cube(double width) { thiswidth = width; } public double calculateVolume() { return width * width * width; } public double calculateFaceArea() { return width * width; } public double getWidth() { return thiswidth; } public void setWidth(double width) { thiswidth = width; } private double width; } 代码清单 Cube类的源代码 package comjavapatternsadaptercubeball; public interface BallIF { double calculateArea(); double calculateVolume(); double getRadius(); void setRadius(double radius); } 代码清单 BallIF接口的源代码 package comjavapatternsadaptercubeball; public class MagicFinger implements BallIF { public MagicFinger(Cube adaptee) { super(); thisadaptee = adaptee; radius = adapteegetWidth(); } public double calculateArea() { return PI * D * ( radius * radius ); } public double calculateVolume() { return PI * D/D * ( radius * radius * radius ); } public double getRadius() { return radius; } public void setRadius(double radius) { thisradius = radius; } private double radius = ; private static final double PI = D; private Cube adaptee; } 代码清单 MagicFinger类的源代码 如果读者还记得中学的数学的话应该可以看出我们的指方为圆系统其实还是有道理的它接受一个正方体 返还此正方体的内切球也就是能放进此正方体的最大的球 显然本例子里我们使用的是实例形式的变压器模式这样做的好处是如果一旦我们决定不仅要支持正方体 而且要支持四面体等多面体我们可以使用同一个MagicFinger类而不必针对每一个多面体都建立一个MagicFinger类 这样也比较符合魔术手指这个名字 关于模式实现的讨论 本模式在实现时有以下这些值得注意的地方 第一目标接口可以省略此时目标接口和源接口实际上是相同的 由于源是一个接口而变压器类是一个类(或抽象类)因此这种做法看似平庸而并不平庸 它可以使客户端不必实现不需要的方法这一点已经在WindowAdapter的例子里做了详尽的分析 第二变压器类可以是抽象类这已经在WindowAdapter的例子里看到了实际上WindowAdapter的例子过于简单 实际的情形里你可能想给出一些实方法 第三带参数的变压器模式使用这种办法变压器类就不必有时可能不能是源类的子类 变压器类根据参数返还一个合适的实例给客户端 问答题 第题请做一个小猫(kittie)的实类并实现miao()catchRat()run()sleep()等方法 再做一个小狗(doggie)的接口要求有wao()fetchBall()run()sleep()等方法 现在你的女朋友想要一只小狗可是你只找到的一只小猫请用变压器模式把小猫适配成小狗 让你的女朋友满意(提示量力而为) 第题请指出第一题的解答所使用的是那一种形式的变压器模式 第题笔者在许多场合给各种不同水准的专业人士作过各种编程模式的介绍发现参加OOP开发工作的不同时间长短的人 对不同的模式理解接受的速度有所不同唯独在讲过这个男朋友与小狗小猫的例子后大家对变压器模式的理解都很准确 让笔者百思不得其解你知道这是怎样回事吗? 第题请讲一讲使用实例形式的变压器模式和使用类形式的变压器模式在第一题的解决上有何影响 问答题答案 第题根据提示我们可以量力而为因此我们将把miao()适配成wao()catchRat()适配成fetchBall() run()sleep()不变源代码如下 图 男朋友小狗适配器的类图 package comjavapatternsadapterkittiedoggie; public interface Doggie { void wao(); void fetchBall(); void run(); void sleep(); void setName(String name); String getName(); } 代码清单 SwingUI类的源代码红色的代码就是使用WindowAdapter的无名内部类 package comjavapatternsadapterkittiedoggie; public class Kittie { public void miao(){} public void catchRat() { } public void run() { } public void sleep() { } public String getName(){ return name; } public void setName(String name){ thisname = name; } } 代码清单 SwingUI类的源代码红色的代码就是使用WindowAdapter的无名内部类 package comja |