Hibernatede的优缺点,Struts的工作流程,延迟加载及理解开闭原则

Hibernate的优点

1.对象/关系数据库映射(ORM)

它使用时只需要操作对象,使开发更对象化,抛弃了数据库中心的思想,完全的面对对象思想

2.透明持久化(persistent)

带有持久化状态、具有业务逻辑的单线程对象,此对象生存期很短。 这些对象可能是普通的JavaBeans/POJO,这个对象没有实现第三方框架或者接口,唯一特殊的是他们正在与(仅仅一个)Session相关联。一旦这个Session被关闭,这些对象就会脱离持久化状态,这样就可以被应用程序的任何层自由使用。(列如,用作跟表示层交互数据和传输对象)。

3.事务Transaction(org.hibernate.Transaction)

应用程序用来指定原子操作的单元范围的对象,它是单线程的,生命周期很短。他通过抽象将应用从底层具体的JDBC、JTA以及CORBA事务隔离开。某些情况下,一个Session

之内可能包含多个Transaction对象。尽管是否使用该对象是可选的,但无论是使用底层的API还是使用Transaction对象,事务边界的开启与关闭是必不可少的。
(4) 它没有侵入性,即所谓的轻量级框架
(5) 移植性会很好
(6) 缓存机制,提供一级缓存和二级缓存
(7) 简洁的HQL编程
 
2. Hibernate缺点
(1)  Hibernate在批量数据处理时有弱势
(2) 针对单一对象简单的增删查改,适合于Hibernate,而对于批量的修改,删除,不适合用Hibernate,这也是OR框架的弱点;要使用数据库的特定优化机制的时候,不适合用Hibernate

Struts2的工作流程

请求在Struts2框架中的处理大概分为以下几个步骤: 1 客户端初始化一个指向Servlet容器的请求; 2 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin) 3 接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action 4 如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy 5 ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类 6 ActionProxy创建一个ActionInvocation的实例。 7 ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。 8 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可 能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper

迟加载与单例模式

延迟加载,也较延迟实例化,延迟初始化等,主要表达的思想就是,把对象的创建延迟到使用的时候创建,而不是对象实例化的时候创建。这种方式避免了性能的浪费。

当创建一个对象的子对象开销比较大时,而且有可能在程序中用不到这个子对象,那么久可以考虑用延迟加载的方式来创建子对象。另外就是当一个程序启动时,需要创建多个对象,但仅有几个对象需要立即使用,那么可以将一些不必要的初始化工作延迟到使用的时候。这样可以提高程序的启动速度。

FramWork4.0中提供了一个包装类Lazy<T>,可以轻松实现延迟加载。

今天就先从延迟加载开始学起。

一、延迟加载

1、Class Singleton

{

        private static Singleton instance;
      private Singleton()
      { }

      public static Singleton getInstance()

      {

         If(instance==null)

{

 Instance=new Singleton();

}

Return instance;

}

}

构造函数私有,方法静态。

问题:无法保证线程安全,当有多个线程同时访问getInstance的时候,此时若对象为空,就会出现会多个线程同时产生多个Singleton对象。

此时我们可以修改一下上面的代码,如下

    public class Singleton
    {  
       private static Singleton instance;
       private static object _lock=new object();

       private Singleton()
       {

       }

       public static Singleton GetInstance()
       {
               if(instance==null)
               {
                      lock(_lock)
                      {
                             if(instance==null)
                            {
                                     instance=new Singleton();
                             }
                      }
               }
               return instance;
       }
    }

上述代码使用了双重锁方式较好地解决了多线程下的单例模式实现。先看内层的if语句块,使用这个语句块时,先进行加锁操作,保证只有一个线程可以访问该语句块,进而保证只创建了一个实例。再看外层的if语句块,这使得每个线程欲获取实例时不必每次都得加锁,因为只有实例为空时(即需要创建一个实例),才需加锁创建,若果已存在一个实例,就直接返回该实例,节省了性能开销。

2、如果使用如下的单例模式

class Singleton
{
 private static Singleton instance = new Singleton();
 private Singleton()
 {
    //
 }
 public static Singleton getInstance()
 {
    return instance;               
 }
}

这个方法保证了在第一次加载的时候实例被初始化,且保证了线程安全。但是为进一步要求,我们想要在使用的时候才才初始化Singleton对象,及延迟加载。那么可以使用如下方法。

3、延迟加载

public class Singleton {
    private Singleton(){
    }
   private static class SingletonHolder

 {
     static Singleton instance = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
    public static void main(String [] args)
    {
        Singleton.getInstance();
    }
}

方法中Singleton 有一个静态内部类SingletonHolder,内部类在外部加载的时候并不会加载,在有在调用getInstance才回加载。另外SingletonHolder类使用Private修饰以确保外部类不能访问。

二、下面再看一个实例

namespace WebApplication2

{

 

    public partial class _Default : System.Web.UI.Page

    {

      

        protected void Page_Load(object sender, EventArgs e)

        {

            // 从数据库中取出数据,得到一个DateRow或者DateRader之类的东东然后初始化一个文章实体类对象

            Model_Article at = 。。。。;//at=getobject();

            // 创建文章分类数据访问对象

            DAO_ArticleCategory articleCategory = new DAO_ArticleCategory();

            subArticle sarticle = new subArticle();

            sarticle.CategoryLazyLoader = articleCategory.GetArticleCategoryById;

            sarticle.CategoryLazyLoader(1);

            Model_ArticleCategory acc = at.Category;

            //

        }

 

    }

    // 文章分类实体类   

    public class Model_ArticleCategory

    {      

        public int CategoryID { get; set; }     

        public string CategoryName { get; set; }  

    }

    public class DAO_ArticleCategory

    {

        public Model_ArticleCategory GetArticleCategoryById(int i)

        {

            return new Model_ArticleCategory();

        }

    }

    // 文章实体类   

    public class Model_Article

    {       

        public int ArticleID { get; set; } 

        public string Title { get; set; }       

        public string Cotnent{ get; set; }       

        public DateTime CreateTime { get; set; }      

        public int CategoryID { get; set; }     

        // 文章所属分类  

        protected Model_ArticleCategory _category;

        public virtual Model_ArticleCategory Category //声明为虚属性

        {

            get

            {

               

                GetCategoryRecord += "获取分类;";

                return _category;

            }

           

        }

        public string GetCategoryRecord { get; set; }

 

    }

    //继承父类,把原来父类中得逻辑放到子类中来实现,保证了父类所处Model层没有引用其他业务层,保证了框架的规则

    public class subArticle : Model_Article

    {

        public override Model_ArticleCategory Category

        {

            get

            {

                if (base._category == null)

                {

                    if (CategoryLazyLoader != null)

                    {

                        _category = CategoryLazyLoader(CategoryID);

                    }

                    else

                    {

                        _category = null;

                    }   

                }

                return base.Category;

            }

        }

        // 文章分类延时加载器(委托)      

        public Func<int, Model_ArticleCategory> CategoryLazyLoader { get; set; }

    }

  

}

基类的Category属性通过返回_category字段的方式返回值,也就是说数据是存在_category字段而不是属性中,但是_category字段怎么才会有值呢,那就是在子类里面通过调用委托拿来的,而这个属性在子类里面不是直接返回的,而是调用基类来返回,这样一来,调用到子类的Category属性的get访问器的时候,先对基类的_categoty字段赋值,然后调用基类的Category属性执行了一些逻辑代码,最后成功地把(已经被赋值的)基类的_categoty字段给返回去。而这一切都是在前面我们实现好的延迟加载的基础上完成的。总结成几个字就是:子类负责延时加载,基类赋值数据存储和返回!

关闭原则的理解

开-闭原则:一个软件实体应该对扩展开放,对修改关闭。


满足开闭原则的模块符合下面两个标准:

  • 对扩展开放 ------- 模块的行为可以被扩展从而满足新的需求。
  • 对修改关闭 ------- 不允许修改模块的源代码。(或者尽量使修改最小化)

这两个标准看似相互矛盾的,那么我们怎么实现他们呢?

怎样实现开闭原则?

  • 抽象
  • 多态
  • 继承
  • 接口
为什么要遵循开放关闭原则?       一个设计良好的应用程序应该充分考虑到开发和维护阶段需求的频繁变化,通常情况下,添加一个新的功能需要做出很多修改,我们应该使对已有代码的修改最小化,因为他们已经经过了测试。对现有代码做出修改将会以一种不可预料的方式影响它们的已有功能。
 
Example:

考虑下面某个类的方法:

Java代码  收藏代码
  1. public double totalPrice(Part[] parts) {  
  2.     double total = 0.0;  
  3.         for (int i=0; i<parts.length; i++) {  
  4.             total += parts[i].getPrice();  
  5.     }  
  6.     return total;  
  7. }  

上面函数的功能是计算给定的零件数组中所有零件价格的总和,如果Part是一个基类或者接口,那我们就可以利用多态的特性,当有新的零件被添加进来时不需要修改该函数的代码。这样它就可以满足开闭原则。

但是如果我们的会计部门规定当计算主板和内存的价格时,需要添加一些额外的费用,请看下面的代码:

Java代码  收藏代码
  1. public double totalPrice(Part[] parts) {  
  2.   double total = 0.0;  
  3.   for (int i=0; i<parts.length; i++) {  
  4.     if (parts[i] instanceof Motherboard)  
  5.       total += (1.45 * parts[i].getPrice());  
  6.     else if (parts[i] instanceof Memory)  
  7.       total += (1.27 * parts[i].getPrice());  
  8.     else  
  9.       total += parts[i].getPrice();  
  10.   }  
  11.   return total;  
  12. }  

现在它还符合开闭原则吗?不!每次会计部门发布一个新的价格政策时,我们都需要修改totalPrice()方法!它对修改不是关闭的,显然,价格政策的改变意味着我们必须修改某处的代码,那么我们应该怎么做呢?为了使用我们第一个版本的totalPrice()方法,我们需要把Part的getPrice()方法的价格政策包含进来。

下面是Part和ConcretePrat类:

Java代码  收藏代码
  1. // Class Part is the superclass for all parts.  
  2. public class Part {  
  3.   private double price;  
  4.   public Part(double price) (this.price = price;}  
  5.   public void setPrice(double price) {this.price = price;}  
  6.   public double getPrice() {return price;}  
  7. }  
  8. // Class ConcretePart implements a part for sale.  
  9. // Pricing policy explicit here!  
  10. public class ConcretePart extends Part {  
  11.     public double getPrice() {  
  12. // return (1.45 * price); //Premium  
  13.       return (0.90 * price); //Labor Day Sale  
  14.     }  
  15. }  

但是,现在如果价格政策改变,我们必须修改Part的子类,一个更好的方法是建立一个PricePolicy类,它可以为我们提供不同的价格政策:

Java代码  收藏代码
  1. /** 
  2. * Class PricePolicy implements a given price policy. 
  3. */  
  4. public class PricePolicy {  
  5. private double factor;  
  6. public PricePolicy (double factor) {  
  7. this.factor = factor;  
  8. }  
  9. public double getPrice(double price) {return price * factor;}  
  10. }  

使用这种方法,我们可以在运行时动态的设置Part对象所引用的PricePoilcy对象,在实际的程序中,零件的价格和相关的PricePolicy可以从数据库中获取。

 
理解: 在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。 
             其实这里所说的不被修改是指的重要的抽象层的模块不会被修改,这也就是使变化中的软 系统有一定的稳定性。当系统要扩展或者添加新的行为的时候只需要添加 另外实现的模块即可。由于新添加的模块继承于抽象层,所以实现了其不变性。 
              比如在策略模式中,OCP就得到了很好的体现,算法的不同实现其实就是对扩展的支持,而算法抽象类是对系统的不变性的支持,环境类包装了对于环境变化的控制与所采用算法的选择,当采用其他算法的时候只需要扩展算法类即可。  
               也就是说关键在于抽象,抽象出来的东西是不变的,具体的实 现继承于抽象,所以保证了对修改的Close,而抽象的实现方式有多种,可以随需添加,当然这也就是对扩展的Open。 另外要求的是技术包括:多态 Polymorphism,接口 Interface,继承 Inheritance.
 
 
注:另外在对可变性进行封装的时候也应该注意以下几点: 
          1.识别系统有可能变化的地方。 
          2.不要将一种可变形散布在多处代码,而应该封装起来。 
          3.不要将一种可变性与另外一种可变性混在一起。
原文地址:https://www.cnblogs.com/hy66668888/p/6178981.html