【文章标题】打造山寨产品和伪造产品的利器——装饰模式
【文章作者】曾健生
【作者邮箱】zengjiansheng1@126.com
【作者QQ】190678908
【作者博客】http://blog.csdn.net/newjueqi
http://newjueqi.iteye.com/
【编程环境】JDK 1.6.0_01
【作者声明】欢迎转载文章,但转载请保留文章的完整性以及注明文章的出处。
*******************************************************************************
现在“山寨文化”和“伪造产品”大行其道,“山寨春晚”“山寨明星”“山寨手机”等等,“伪造产品”就更加不用说了,广大群众也深受其害(本人也是其中一位受害者!!!)不说不知道,在学设计模式的过程中本人一不小心发现了装饰模式是有很强的“伪造功能”(“伪造功能”是指把别人写的类,功能模块等包装一下换成自己写的,但其实核心还是别人写的代码)和“山寨功能”(利用类提供的接口添加代码增强类的功能)。
《设计模式:可复用面向对象软件的基础》是这样定义装饰模式(Decorator):动态地给一个对象添加一些额外的职责,就增加功能来来说,装饰模式比生成子类更加灵活。
一般来说,实现装饰器模式可分为下面3步:
1. 建立包装类,定义构造函数接收包装对象
2. 建立成员引用,让被包装对象作用于整个包装类
3.根据需要增加一些功能函数已增强类的功能
如果我们把装饰器模式实现“伪造功能”,就分为以下3步(非常邪恶的!!!):
1. 建立包装类,定义构造函数接收包装对象的参数
2. 建立成员引用,让被包装对象作用于整个包装类
3. 用自定义的函数封装包装对象的函数
以前有个著名的“汉芯造假”事件,大概就是说把某个外国芯片的标识去掉,然后改头换面,就变成了所谓的“汉芯”了。用装饰器模式实现“伪造功能”模拟这个过程的代码如下:
//一个美国芯片类,这个芯片类有三个功能:
//1.显示自身的信息
//2.获得两个数相加的结果
//3.获得两个数相减的结果
class AmericanChip
{
//美国芯片类的构造函数
AmericanChip( ){}
//美国芯片类显示自身信息的函数
public void printInfo()
{
System.out.println( "我是美国的芯片" );
}
//获得两个数相加的结果
public double add( double x, double y )
{
return x+y;
}
//获得两个数相减的结果
public double sub( double x, double y )
{
return x-y;
}
}
//这是造假芯片类,把美国的芯片改头换面后完成的
//步骤分为三步:
//1.建立包装类,定义构造函数接收包装对象的参数
//2.建立成员引用,让被包装对象作用于整个包装类
//3.用自定义的函数封装包装对象的函数
class FakeChip
{
//建立被包装类的引用
private AmericanChip americanChip;
FakeChip( )
{
//构造美国的芯片类的实例
this.americanChip=new AmericanChip();
}
//造假芯片类显示自身信息的函数,这个函数就相同于把美国芯片的标识去掉,换上“汉芯”的标识
public void printInfoFake()
{
System.out.println( "我是造假芯片" );
}
//造假芯片类通过美国芯片类获得两个数相加的结果
public double addFake( double x, double y )
{
return americanChip.add( x, y );
}
//造假芯片类通过美国芯片类获得两个数相减的结果
public double subFake( double x, double y )
{
return americanChip.sub( x, y );
}
}
造假芯片类FakeChip共暴露了3个接口:
1. public void printInfoFake()
2. public double addFake( double x, double y )
3. public double subFake( double x, double y )
从代码可看出,除了printInfoFake()方法是显示自身的信息外(造假产品要先显示一下自身的产品信息使别人误认为是正牌货),其他的两个方法addFakehe 和 subFake实际上是调用了美国芯片类的相关方法,这就模拟了“汉芯”造假的过程。
可能有的读者可能问使用继承不是能实现这个结果吗?选用装饰器模式而不用继承有两个原因:
1. 装饰器模式可选择需要暴露被包装类(美国芯片类AmericanChip)的哪些公有函数,虽然也可以用继承后覆盖同名函数的方法实现,但如果包装类(美国芯片类AmericanChip)的公有函数非常多的话,那真的写代码写得人崩溃!!!
2. 可把被包装类(美国芯片类AmericanChip)的公有函数用间接实现改名调用,真正实现改头换面的目的。
虽然本文前面论述的内容是怎么用装饰器模式实现“造假”过程,但我们必须要明白一个事实:装饰器模式的出现是为了给子类添加新的功能提供方便性和灵活性,这个才是装饰器模式的最主要用途。
在java的IO类中有个类FileInputStream用来处理文件数据的,另外还有一个类BufferedInputStream提供了缓冲区的功能,大家认真比较一下BufferedInputStream和FileInputStream的函数,发现多了缓冲的功能外,其他的实现都是很相近的,另外查找一下BufferedInputStream的构造函数BufferedInputStream
(InputStream in),能发现
BufferedInputStream的实例化是传入了InputStream的对象,大家有没有发现和前面论述的实现装饰器模式的三步非常像,虽然在源码里BufferedInputStream的实现比较麻烦,但我们可用装饰器模式的思想,实现一个“山寨版BufferedInputStream”类。
//这是山寨版的BufferedInputStream类MyBufferedInputStream
package newjueqi.net.csdn.MyBufferedInputStream;
//这是山寨版的BufferedInputStream类MyBufferedInputStream
import java.io.*;
class MyBufferedInputStream
{
private int num=0;//读入字节的个数
private int pos=0;//当前在数组中的下标
//实现装饰器模式步骤2:建立成员引用,让被包装对象作用于整个包装类
private InputStream inputstream_temp=null; //字节流的引用
private byte buf[]=new byte[1024]; //缓冲区数组
byte temp=0;
//实现装饰器模式步骤1:建立包装类,定义构造函数接收包装对象
MyBufferedInputStream( InputStream inputstream_temp )
{
this.inputstream_temp=inputstream_temp;
}
//实现装饰器模式步骤3:根据需要增加一些功能函数已增强类的功能
//用缓冲区增强了读取的功能
public int myRead()
{
//把缓冲区的数据填满
if( num==0 )
{
try {
//num中保存了读入缓冲区的字节的个数
num=inputstream_temp.read(buf);
pos=0;
//表示已读到文件尾,返回-1
if( num<0 )
return -1;
temp=buf[pos];
num--;
pos++;
//为了防止读入数据如果为11111111后类型转换后变成
//-1,所以要把多余位上的1去掉用&运算
return temp&0xff;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return -1;
}
}
else if( num>0 ) //取出缓冲区中的数据
{
temp=buf[pos];
num--;
pos++;
return temp&0xff;
}
return -1;
}
//关闭字节流
public void close()
{
try {
inputstream_temp.close();
} catch (IOException e) {
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)