欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

设计模式-三种工厂模式实例

程序员文章站 2022-04-30 23:42:02
1.简单工厂模式:代替new产生对象,产品的类型比较少时。 我们要获得三种不同的数据库对象,如Mysql,SQLserver,Oracle,它们拥有共同的特征,即可以进行抽象,简单工厂目的是将获得具体数据库实体的任务交给工厂类。 接口DataBase: 类Mysql: 类Oracle: 类SQLse ......

  1.简单工厂模式:代替new产生对象,产品的类型比较少时。

      我们要获得三种不同的数据库对象,如mysql,sqlserver,oracle,它们拥有共同的特征,即可以进行抽象,简单工厂目的是将获得具体数据库实体的任务交给工厂类。

 接口database:

public interface database {
         public void open();
         public void close();
}

 类mysql:

public class mysql implements database {
    @override
    public void open() {
        system.out.println("open mysql");    
    }

    @override
    public void close() {
       system.out.println("close mysql");
        
    }
}

类oracle:

public class oracle implements database {
    @override
    public void open() {
       system.out.println("open oracle");
        
    }
    @override
    public void close() {
      system.out.println("close oracle");    
    }
}

类sqlserver:

public class sqlserver implements database {
    @override
    public void open() {
     system.out.println("open sqlserver");    
    }
    @override
    public void close() {
        system.out.println("close sqlserver");    
    }
}

 

工厂类及测试:

public class factory {
     public database getdatabase(string type){
          if(type == null){
             return null;
          }        
          if(type.equalsignorecase("mysql")){
             return new mysql();
          } else if(type.equalsignorecase("oracle")){
             return new oracle();
          } else if(type.equalsignorecase("sqlserver")){
             return new sqlserver();
          }
          return null;
       }
     @test
     public void test(){
          factory factory = new factory();      
          database d1= factory.getdatabase("mysql");
          d1.open();
          database d2= factory.getdatabase("oracle");
          d2.open();
          database d3= factory.getdatabase("sqlserver");
          d3.open();
     }
     
}

      特点: 如果要新增其他数据库,只需创建新数据库类实现功能接口,修改工厂类。

                 问题1:根据“开闭原则”:对现有功能进行拓展,但不允许修改原有代码。很明显,这时简单工厂模式需多次修改工厂类。

                 问题2:使用者实际使用时并不知道类名,他只知道有database这个接口,使用这个接口就能创建对象,使用open()函数,当然实际中肯定还需传入用户名和密码等参数。

针对问题2:可以使用枚举的方式,代码如下:

public class factory2 {
    enum databasetype{
        mysql,
        sqlserver,
        oracle
    } 
    public static database getdatabase(databasetype type){
        switch(type){
            case mysql:
                return new mysql();
            case oracle:
                return new oracle();
            case sqlserver:
                return new sqlserver();
            default:
                throw new unknowntypeexception(null, type);
        }
    }
   @test
   public void test(){
       database s1=factory2.getdatabase(databasetype.mysql);
       s1.open();
       database s2=factory2.getdatabase(databasetype.oracle);
       s2.open();
   }
}

 

 2.工厂方法模式(factory method):定义一个用于创建对象的接口,让子类决定实例化哪一个类,使一个类的实例化延迟到其子类。

       使用简单工厂方式使得工厂函数很难维护,而且请求者还需知道被实例化的类,而工厂方法模式可避免之。

       新建抽象工厂 ifactory,对于每个数据库都新建相应的工厂类,如mysqlfactory,oraclefactory实现 ifactory,这样在新增一种数据库时,不必修改工厂类而造成破坏封闭原则。

public interface ifactory {
    public  database get();
}

 

class sqlfactory implements ifactory{
       public database get(){
           return new mysql();
       }
}
class oraclefactory implements ifactory{
    public database get(){
        return new oracle();
    }
}
 class sqlserverfactory implements ifactory{
     public database get(){
        return new sqlserver();
    }
}
 //测试  
 public class factorymethod{ 
     public static void main(string[] args){
         database d1=new sqlfactory().get();
         d1.open();
     }
 }

       问题1:如果数据库类型越来越多,将无限的增加工厂子类,使用者同样还是需要知道工厂子类的名称。

       问题2:在使用时数据库时可能还需与其他的类相关联,工厂方法模式无法解决。

3.抽象工厂模式(abstract factory):提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类。

      场景:若在新建数据库连接时需指定方言,而且不同数据库的sql语言也不相同的情况下。

      组成元素:

       1.方言类和接口,如图所示:

  设计模式-三种工厂模式实例

      2.之前的数据库类和接口

     设计模式-三种工厂模式实例

      3.operfactory抽象工厂

public  abstract class operfactory{
        private idialect dialect;       
        abstract void  add();
        abstract void  delete();
        abstract void  update();
        public void setdialect(string classname){
                idialect cf=null;
                try {
                    cf=(idialect)class.forname(classname).newinstance();
                    setdialect(cf);
                } catch (instantiationexception | illegalaccessexception | classnotfoundexception e) {
                    e.printstacktrace();
                }
        }
        public idialect getdialect() {
            return dialect;
        }
        public void setdialect(idialect dialect) {
            this.dialect = dialect;
        }
        
}

 

  4. mysqlfatory,oraclefactory( 均继承上面的抽象工厂类)

public class mysqlfatory extends operfactory {
    @override
    void add() {    
        system.out.println("使用的方言为:"+this.getdialect().showdialect());
        system.out.println("mysql add()");
    }
    @override
    void delete() {
        system.out.println("使用的方言为:"+this.getdialect().showdialect());
        system.out.println("mysql delete()");
    }
    @override
    void update() {
        system.out.println("使用的方言为:"+this.getdialect().showdialect());
        system.out.println("mysql update()");
    }
    
    
}
public class oraclefactory extends operfactory {
    @override
    void add() {
        system.out.println("使用的方言为:"+this.getdialect().showdialect());
        system.out.println("oracle add()");
    }
    @override
    void delete() {
        system.out.println("使用的方言为:"+this.getdialect().showdialect());
        system.out.println("oracle delete()");
        
    }
    @override
    void update() {
        system.out.println("使用的方言为:"+this.getdialect().showdialect());
        system.out.println("oracle update()");
        
    }


}

 

      5.工厂构造器类 factoryproducer 负责生成想要的数据库工厂。

public class factoryproducer {
       public static operfactory getfactory(string class_name) {
         operfactory cf=null;
        try {
            cf=(operfactory)class.forname(class_name).newinstance();
        } catch (instantiationexception | illegalaccessexception | classnotfoundexception e) {
            e.printstacktrace();
        }
        return cf;    
    }
}

 

  6.测试

public static void main(string[] args){  
          operfactory of2=factoryproducer.getfactory(databasefactorytype.mysql);
          of2.setdialect(dialecttype.mysql5innodbdialect);
          of2.update();
          
          operfactory of= factoryproducer.getfactory(databasefactorytype.oralce);
          of.setdialect(dialecttype.oracle10gdialect);
          of.add();
      }

 

 结果:

 设计模式-三种工厂模式实例

  总之抽象工厂总是关于创建一系列相关或相互有依赖的对象,以上例子中即database对象与dialect对象具有相关性。但是使用者要了解各种工厂和方言。

三者区别:

           简单工厂实现简单,扩展也很容易,但是会频繁修改工厂类代码,难以维护,在维护的时候容易引发新的bug。

           工厂方法模式则是把对象的实例化延迟到了继承的子类里面,这样就变成了扩展工厂,从而满足了“开闭”原则, 但是不支持产品切换,也就是只能满足一层的产品(算法)抽象,当需与其他对象合作时无能为力。

            抽象工厂则是继续把产品进行再次抽象,最后得到一个可以支持产品切换的结构,但问题过于复杂,不过我们使用反射机制,可以弥补这个缺点,但是使用者却需要知道工厂的名称。

 

            以上工程源码分享:链接:https://pan.baidu.com/s/1elhalizkrr1n7391jw8uta    密码:1ikz