在Java中,有两种常用的设计模式:
●单例模式●工厂模式
单例模式可以使得实现同一个接口的所有不同类的对象共享接口中的同一个对象,,可以大大降低Java对象在创建和销毁时的系统开销;工厂模式可以将Java对象的调用者从被调用者的实现逻辑中分离出来,调用者只需关心被调用者必须满足的规则(接口),而不必关心实例的具体实现过程。这是面向接口编程的优势,能提高程序的解耦,避免所有的类以硬编码的方式耦合在一起。
1.单例模式的介绍
单态模式限制了类实例的创建,但采用这种模式设计的类,可以保证仅有一个实例,并可提供访问该实例的全局访问点。J2EE应用的大量组件,都需要保证一个类只有一个实例。比如数据库引擎访问点只有一个。
更多的时候,为了提高性能,程序应尽量减少Java对象的创建和销毁时的开销,这样就能保证了只能通过静态方法获得类的实例。而该静态方法则保证每次返回的实例都是同一个,这就需要将该类的实例设置成类属性,由于该属性需要被静态方法访问,因此该属性应该设置成静态属性。
下面给出单态模式的示例代码:
package test;
public class SingletonTest {
//该类的一个属性
int value;
//使用静态属性保存该类的一个实例
private static SingletonTest instance;
//构造器私有化,避免该类被多次实例
private SingletonTest(){
System.out.println("正在执行构造器...");
}
//提供静态方法来返回该类的实例
public static SingletonTest getInstance(){
//实例化类之前,先检查该类的实例是否存在
if(instance == null){
//如果不存在,则新建一个实例
instance = new SingletonTest();
}
//存在则返回该类的成员变量:该类的实例
return instance;
}
//以下提供对普通属性value的setter和getter方法
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public static void main(String[] args){
SingletonTest t1 = new SingletonTest().getInstance();
SingletonTest t2 = new SingletonTest().getInstance();
t2.setValue(9);
System.out.println(t1 == t2);
}
}
运行结果如下:
正在执行构造器...
正在执行构造器...
正在执行构造器...
true
从程序的最后打印结果可以看出,该类的两个实例完全相同。这证明了单例模式类的全部实例都是同一共享实例。
2.工厂模式的介绍
工厂模式是根据调用数据返回某个类的一个实例,此类可以是多个类的某一个类。通常,这些类满足共同的规则(接口)或者父类,调用者只关心工厂生产的实例是否满足某种规范,即是实现的某个接口是否可以供自己正常调用(调用者仅仅使用)。该模式给对象之间做出了清晰的角色划分,降低程序的耦合。
接口产生的全部实例通常用于实现相同的接口,接口里定义了全部实例共同拥有的方法,这些方法在不同的实现类中实现的方式不同。从而使程序调用者无需关心方法的具体实现,降低了系统异构的代价。
下面是工厂模式的实例:
(1)先创建一个接口:
package test;
public interface Person {
//定义一个打招呼的函数
public String sayHello(String name);
//定义一个告别的函数
public String sayGoodBye(String name);
}
(2)创建两个实现接口的类:
package test;
public class American implements Person {
@Override
public String sayHello(String name) {
return name+",hello";
}
@Override
public String sayGoodBye(String name) {
return name+",GoodBye";
}
}
package test;
public class Chinese implements Person {
@Override
public String sayHello(String name) {
return name+",您好";
}
@Override
public String sayGoodBye(String name) {
return name+",下次再见";
}
}
(3)创建一个工厂类:
package test;
public class PersonFactory {
//获得Person实例的实例工厂方法
//调用该实例工厂方法传入的参数
//return 返回Person实例
public Person getPerson(String ethnic){
//根据参数ethnic返回Person接口的实例
if(ethnic.equalsIgnoreCase("chin")){
return new Chinese();
}
else{
return new American();
}
}
}
(4)编写测试类:
package test;
public class FactoryTest {
public static void main(String[] args){
//创建PersonFactory的实例,获得工厂实例
PersonFactory pf = new PersonFactory();
//定义接口Person的实例,面向接口编程
Person p = null;
//使用工厂获得Person的实例
p = pf.getPerson("chin");
//下面调用Person接口的方法
System.out.println(p.sayHello("wawa"));
System.out.println(p.sayGoodBye("wawa"));
//使用工厂获得Person的另一个实例
p = pf.getPerson("ame");
//再次调用Person接口的方法
System.out.println(p.sayHello("wawa"));
System.out.println(p.sayGoodBye("wawa"));
}
}
运行测试类,结果如下:
wawa,您好
wawa,下次再见
wawa,hello
wawa,GoodBye
由此可以看出,主程序从Person接口的具体类中解耦出来,而且程序调用者无需关心Person的实例化过程,主程序仅仅与工厂服务定位结合在一起,可以获得所有工厂能产生的实例。具体类的实现,接口无需发生任何改变,调用程序代码部分也无需发生任何改动。