软件的结构对系统整体性能有着重要的影响,优秀的设计结构可以规避很多潜在的性能问题,对系统性能的影响可能远远大于代码的优化。
善用设计模式
1、单例模式
单例模式是设计模式中使用最为普遍的模式之一,他是一种对象创建模式,用于产生一个对象的具体实例,他可以确保系统中一个类只产生一个实例。
两大好处:①、对于频繁使用的对象,可以省略创建对象所花的时间。(尤其对于重量级对象而言,是非常可观的一笔开销);
②、由于New操作的次数减少,因而系统内存的使用频繁也会降低。(这将减轻GC的压力,缩短GC停顿的时间);
综上所述:对于系统的关键组件和被频繁使用的对象而言使用单例模式可以有效地提升系统的性能。
单例模式例子:
public class Singleton {
private Singleton(){ //单例类中必须有一个private访问级别的构造函数,只有这样才能确保单例不会在系统中其他代码内被实例化
System.out.println("Singleton is create"); //创建单例的过程可能会比较慢
}
private static Singleton instance;
public static Singleton getInstance(){
if(instance==null){
instance = new Singleton();
}
return instance;
}
public void ceshi(){
System.out.println("我就使用了");
}
public static void main(String[] args) {
Singleton.getInstance().ceshi();
}
}
2、享元模式
享元模式是设计模式中少数几个以提高系统性能为目的的模式之一。
它的核心思想是:系统中存在多个相同的对象,那么就共享一份对象的拷贝,不必为每一次使用都创建新的对象,由于需要构造和维护这些可以共享的对象,因此会出现一个工厂类,用于维护和创建对象。
两大优点:①、可以节省重复创建对象的开销,因为被享元模式维护的相同对象只会被创建一次,所以可以节省大量的创建对象消耗时间。
②、由于创建对象的数量减少,所以对系统内存的需求也减小了,这将使得GC的压力也相应降低,进而使系统拥有一个更健康的内存结构和更快的反应速度。
享元模式的主要由享元工厂、抽象享元、具体享元类和主要函数几部分组成。
角色 | 作用 |
享元工厂 | 用以创建具体享元类,维护相同的享元对象。它保证相同的享元对象可以被系统共享。其内部使用了单例模式的算法,当请求对象已经存在时,直接返回对象,不存在时,再创建对象 |
抽象享元 | 定义需共享的对象的业务接口。享元类被创建出来总是为了实现某些特定的业务逻辑,而抽象享元便定义这些逻辑的语义行为 |
具体享元类 | 实现抽象享元类的接口,完成某一具体逻辑 |
Main | 使用享元模式的组件,通过享元工厂取得享元对象 |
注意:享元模式与对象池(数据库链接池)是不同的,对象池中的所有对象都是等价的,可以任意两个对象都可以被对象池中的其他对象代替,但是在享元模式中所有对象都是不同的,不能被代替。
实际使用环境举例:SAAS系统就是使用享元模式的一个典型的应用。
以人事管理系统的SAAS软件系统为例,假设公司甲、乙、丙均为SAAS系统的用户,则定义每个公司为这套系统中的一个租户。每个公司(租户)又各自有100个员工,如果这些公司的所有员工都可以登录这套系统查看自己的收入情况,为了系统安全,每个公司(租户)都拥有自己独立的数据库。这种情况下就需要使用享元模式为每个租户分别提供一个工资查询接口,而每个公司(租户)下的所有员工可以共享一个查询。这样系统只需要3个享元实例,就足以应付300个员工的查询请求了。
创建抽象享元
public interface IReportManager {
public String createReport();
}
具体享元类实现
public class FinancialReportManager implements IReportManager {
protected String tenantId = null;
public FinancialReportManager(String tenantId){
this.tenantId = tenantId;
}
/* (non-Javadoc)
* @see text.IReportManager#createReport()
*/
@Override
public String createReport() {
// TODO Auto-generated method stub
return "This is a financial report-------"+tenantId;
}
}
创建享元工厂
public class ReportManagerFactory {
Map<String, IReportManager> financialReportManager = new HashMap<String, IReportManager>();
IReportManager getFinancialReportManager(String tenantId){
IReportManager r = financialReportManager.get(tenantId);
if(r==null){
r = new FinancialReportManager(tenantId);
financialReportManager.put(tenantId, r);
}
return r;
}
}
使用享元模式的方法
public static void main(String[] args) {
ReportManagerFactory rmf = new ReportManagerFactory();
IReportManager rm = rmf.getFinancialReportManager("a");
System.out.println(rm.createReport());
}
3、装饰者模式
装饰者模式拥有一个设计非常巧妙的结构,它可以动态添加对象功能。在基本的设计原则中,有一条重要的设计准则叫做合成/聚合复用原则。根据该原则的思想,代码复用应该尽可能的使用委托,而不是使用继承。因为继承是一种紧密耦合,任何父类的改动都会影响其子类,不利于系统维护。而委托则是松散耦合,只要接口不变,委托类的改动并不会影响上层对象。
装饰者模式主要由组件接口、具体组件、装饰者、具体装饰者几个角色组成。
角色 | 作用 |
组件接口 | 组件接口是装饰者和被装饰者的超类或者接口。它定义了被装饰者的核心功能和装饰者需要加强的功能点 |
具体组件 | 具体组件实现了组件接口的核心方法,完成某一个具体的业务逻辑。他也是被装饰者的对象 |
装饰者 | 实现组件接口,并持有一个具体的被装饰者对象 |
具体装饰者 | 具体实现装饰的业务逻辑,既实现了被分离的各个增强功能点。各个具体装饰者是可以相互叠加的,从而可以构成一个功能更强大的组件对象 |
在JDK的实现中,有不少组件也是用装饰者模式实现。其中一个最典型的例子就是OutputStream和InputStream类族的实现。
创建组件接口
public interface IPacketCreator {
public String handleContent(); //用于内容处理
}
具体组件(被装饰者)
public class PacketBodyCreator implements IPacketCreator {
/* (non-Javadoc)
* @see sjms.zsz.IPacketCreator#handleContent()
*/
@Override
public String handleContent() {
// TODO Auto-generated method stub
return "Content of Packet"; //构造核心数据,但不包括格式
}
}
创建装饰者(负责告知其子类,其核心业务逻辑应该全权委托component完成,自己仅仅是做增强处理)
public abstract class PacketDecorator implements IPacketCreator {
IPacketCreator component;
/* (non-Javadoc)
* @see sjms.zsz.IPacketCreator#handleContent()
*/
public PacketDecorator(IPacketCreator c){
component = c;
}
}
具体装饰者
//对发布的内容进行HTML格式化操作
public class PacketHTMLHeaderCreator extends PacketDecorator {
public PacketHTMLHeaderCreator(IPacketCreator c) {
super(c);
// TODO Auto-generated constructor stub
}
/* (non-Javadoc)
* @see sjms.zsz.IPacketCreator#handleContent()
*/
@Override
public String handleContent() {
// TODO Auto-generated method stub
StringBuffer sb = new StringBuffer();
sb.append("<html>");
sb.append("<body>");
sb.append(component.handleContent());
sb.append("</body>");
sb.append("</html>\n");
return sb.toString();
}
}
//对发布的内容进行HTTP头部的处理
public class PacketHTTPHeaderCreator extends PacketDecorator {
public PacketHTTPHeaderCreator(IPacketCreator c) {
super(c);
// TODO Auto-generated constructor stub
}
/* (non-Javadoc)
* @see sjms.zsz.IPacketCreator#handleContent()
*/
@Override
public String handleContent() {
// TODO Auto-generated method stub
StringBuffer sb = new StringBuffer();
sb.append("Cache-Control:no-cache\n");
sb.append("Date:Mon,31Dec201204:25:57GMT\n");
sb.append(component.handleContent());
return sb.toString();
}
}
使用装饰者模式的方法
public class Main {
public static void main(String[] args) {
IPacketCreator pc = new PacketHTTPHeaderCreator(new PacketHTMLHeaderCreator(new PacketBodyCreator()));
System.out.println(pc.handleContent());
}
}
4、观察者模式
观察者模式是非常常用的一种设计模式。在软件系统中,当一个对象的行为依赖于另一个对象的状态时,观察者模式就相当适用。(适用于一对多)
注意:观察者模式可以用于事件监听、通知发布等场合。可以确保观察者在不使用轮询监控的情况下,及时收到相关消息和事件。
观察者模式由主题接口、具体主题、观察者接口、具体观察者几个角色组成。
角色 | 作用 |
主题接口 | 指被观察者的对象。当其状态发生改变或者某事件发生时,它会将这个变化通知观察者。它维护了观察者所需要依赖的状态 |
具体主题 | 具体主题实现了主题接口中的方法。如新增观察者、删除观察者和通知观察者。其内部维护了一个观察者列表 |
观察者接口 | 观察者接口定义了观察者的基本方法。当依赖状态发生改变时,主题接口就会调用观察者的update方法 |
具体观察者 | 实现了观察者接口的update(),具体处理当被观察者状态改变或者某一时间发生时的业务逻辑 |
主题接口:
public interface ISubject {
void attach(IObserver iobserver); //添加观察者
void detach(IObserver iobserver); //删除观察者
void inform(String str); //通知所有观察者
}
具体主题:
public class ConcreteSubject implements ISubject{
List<IObserver> observers = new ArrayList<IObserver>();
@Override
public void attach(IObserver iobserver) {
// TODO Auto-generated method stub
observers.add(iobserver);
}
@Override
public void detach(IObserver iobserver) {
// TODO Auto-generated method stub
observers.remove(iobserver);
}
@Override
public void inform(String str) {
// TODO Auto-generated method stub
for(IObserver iobserver:observers){
if(iobserver==null){
continue;
}
iobserver.update(str);
}
}
}
观察者接口:
public interface IObserver {
void update(String str);
}
具体观察者:
public class ConcreteObserver implements IObserver {
/* (non-Javadoc)
* @see sjms.gcz.IObserver#update(java.lang.String)
*/
@Override
public void update(String str) {
// TODO Auto-generated method stub
System.out.println("Update String = " +str);
}
}
观察者模式的使用:
public class Main {
public static void main(String[] args) {
ISubject isubject = new ConcreteSubject();
IObserver iobserver1 = new ConcreteObserver();
IObserver iobserver2 = new ConcreteObserver();
isubject.attach(iobserver1);
isubject.attach(iobserver2);
isubject.detach(iobserver2);
isubject.inform("开心");
}
}