Android设计模式------对象创建模式

对象创建模式应用场景

通过“对象创建”模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖工具类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。

典型模式

  • Factory Method
  • Abstract Factory
  • Prototype
  • Builder

Factory Method 工厂方法

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:主要解决接口选择的问题。

何时使用:我们明确地计划不同条件下创建不同实例时。

如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

关键代码:创建过程在其子类执行。

应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 2、Hibernate 换数据库只需换方言和驱动就可以。

优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。

注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

应用场景

在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。

模式定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的: 解耦,手段:非静态方法)到子类。

类图结构

 

比如制作一个文件分割器


//每种类型的分割器 分隔算法都不一样
abstract class ISplitter{
    public abstract void split();
}

//二进制文件分割器
class BinarySplitter extends ISplitter{

    @Override
    public void split() {

    }
}

//文本文件分割器
class TxtSplitter extends ISplitter{

    @Override
    public void split() {

    }
}

//图片文件分割器
class PictureSplitter extends ISplitter{

    @Override
    public void split() {

    }
}

//视频文件分割器
class VideoSplitter extends ISplitter{

    @Override
    public void split() {

    }
}

class MainActivity extends Activity {

    private EditText txtFilePath;
    private EditText txtFileNumber;
    private ProgressBar progressBar;

    public void buttonClick(){
		//接口依赖 MainActivity 依赖于接口(抽象类)  接口和抽象 表达松耦合思想是一样的
		//不符合依赖倒置原则 尽可能去依赖抽象类 不要去依赖具体类 因为具体类随着需求的变更是易变的 
        ISplitter splitter=new BinarySplitter();//依赖具体类
        splitter.split();
    }
}

 工厂方法 就是为了 解决 想创建具体类 但是不想在代码中以编译时的依赖方式去依赖具体类。

//抽象类
abstract class ISplitter{
    public abstract void split();
}


//工厂基类
abstract class SplitterFactory{
	//用于创建对象的接口
    public abstract ISplitter createSplitter();

}
//具体类
class BinarySplitter extends ISplitter {

    @Override
    public void split() {

    }
}

class TxtSplitter extends ISplitter {

    @Override
    public void split() {

    }
}

class PictureSplitter extends ISplitter {

    @Override
    public void split() {

    }
}

class VideoSplitter extends ISplitter {

    @Override
    public void split() {

    }
}

//具体工厂  让子类决定实例化哪一个类
//使用方法return 返回一个对象 创建对象 
//创建对象三种方式 1.new出来 2. 使用反射(性能极低) 3. 通过方法返回对象
class BinarySplitterFactory extends SplitterFactory {
    @Override
    public ISplitter createSplitter() {
        return new BinarySplitter();
    }
}

class TxtSplitterFactory extends SplitterFactory{
	//Factory Method使得一个类的实例化延迟(目的: 解耦,手段:非静态方法)到子类。
	//延迟 就是把 编译时 延迟到 运行时 编译时早 运行时晚 
    @Override
    public ISplitter createSplitter() {
        return new TxtSplitter();
    }
}


class PictureSplitterFactory extends SplitterFactory{
    @Override
    public ISplitter createSplitter() {
        return new PictureSplitter();
    }
}

class VideoSplitterFactory extends SplitterFactory{
    @Override
    public ISplitter createSplitter() {
        return new VideoSplitter();
    }
}
class MainActivity extends Activity{

    SplitterFactory factory;

    public MainActivity(SplitterFactory factory){
        this.factory=factory;
    }

    public void buttonClick(){
		//new 本来不是多态的 new后面跟着什么类型就创建什么对象 是编译时绑定
		//createSplitter()创建的对象 还不一定 具体要看 factory 是什么类型、
		//把变化让运行时 执行   延迟到运行时的做法
        ISplitter splitter1=factory.createSplitter();//多态new
        splitter1.split();

		//工厂factory在实际开发中会被 调用多次
        ISplitter splitter2=factory.createSplitter();//多态new
        splitter2.split();
    }
}

结构中的Product 对应代码中的是 ISplitter  抽象产品接口。ConcreteProduct 对应的是 TxtSplitter,BinarySplitter,PictureSplitter,VideoSplitter。Creator 对应的是 SplitterFactory。FactoryMethod() 对应的是 createSplitter()。ConcreteCreator
对应的是 BinarySplitterFactory,TxtSplitterFactory,PictureSplitterFactory,VideoSplitterFactory。

Product 和 Creator 是稳定的,在编译时依赖,是抽象的。ConcreteProduct 和 ConcreteCreator 是变化的,在运行时创建出来的。

要点总结

    FactoryMethod模式用于隔离类对象的使用者和具体类型之间的耦合关系(隔离MainActivity和new BinarySplitter() 具体类之间的依赖关系)。面对一个经常变化的具体类型(BinarySplitter 以后可能变成 VideoSplitter或者其他),紧耦合关系(new)会导致软件的脆弱。
   Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。(比如 BinarySplitterFactory extends SplitterFactory 继承即可 在MainActivity 中只需要 ISplitter splitter1=factory.createSplitter();//多态new  增加一行代码 创建对象即可 )
   Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。

 

Abstract Factory 抽象工厂

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

主要解决:主要解决接口选择的问题。

何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

如何解决:在一个产品族里面,定义多个产品。

关键代码:在一个工厂里聚合多个同类产品。

应用实例:工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况(现实中是不存在的,要不然,没法进入共产主义了,但有利于说明抽象工厂模式),在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。

优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。

注意事项:产品族难扩展,产品等级易扩展。

应用场景 

在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。

 模式定义

提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。

类图结构

比如要设计一个数据访问层

public class EmployeeDAO {

    public Vector<EmployeeDO> getEmployeeDOs() {
		//使用 new 创建对象 要思考以后对象是否会有变化
		//比如现在 需求是使用 MySQL数据库 如果后面客户需要支持SQLServer或者Oracle,DB2
		//这时候 就需要修改连接对象,命令对象,读取器了
		//连接对象
        MySqlConnection connection=new MySqlConnection();
        connection.setConnectionString("...");
		
		//命令对象
        MySqlCommand command=new MySqlCommand();
        command.setCommandText("...");
        command.setConnection(connection);
		
		//读取器
        MySqlDataReader reader=command.executeReader();
        while (reader.read()){

        }

        return employeeDOs;
    }

}

 使用工厂方法解决问题

//数据库访问有关的基类 数据库连接抽象类
abstract class IDBConnection {

}
//创建连接工厂
abstract class IDBConnectionFactory {
    public abstract IDBConnection createDBConnection();
}

//数据库命令抽象类
abstract class IDBCommand {
}
//创建命令工厂
abstract class IDBCommandFactory {
    public abstract IDBCommand createDBCommand();
}

//数据库读取抽象类
abstract class IDataReader {

}
//创建读取器工厂
abstract class IDataReaderFactory {
    public abstract IDataReader createDataReader();
}


//支持My SQL
class MySqlConnection extends IDBConnection {

}

class MySqlConnectionFactory extends IDBConnectionFactory {

    @Override
    public IDBConnection createDBConnection() {
        return new MySqlConnection();
    }
};


class MySqlCommand extends IDBCommand {

}

class MySqlCommandFactory extends IDBCommandFactory {

    @Override
    public IDBCommand createDBCommand() {
        return new MySqlCommand();
    }
}


class MySqlDataReader extends IDataReader {

}

class MySqlDataReaderFactory extends IDataReaderFactory {

    @Override
    public IDataReader createDataReader() {
        return new MySqlDataReader();
    }
}

//支持Oracle
class OracleConnection extends IDBConnection {

}

class OracleConnectionFactory extends IDBConnectionFactory {

}

class OracleCommand extends IDBCommand {

}
class OracleCommandFactory extends IDBCommandFactory {

}

class OracleDataReader extends IDataReader {

}
class OracleDataReaderFactory extends IDataReaderFactory {

}


class EmployeeDAO {
	//声明数据库所需的工厂
    IDBConnectionFactory dbConnectionFactory;  //如果给的是 MySql的ConnectionFactory
    IDBCommandFactory dbCommandFactory;         //如果给的是 Oracle的 CommandFactory
    IDataReaderFactory dataReaderFactory;		//如果给的是 DB2的 ReaderFactory
	//这几个Connection Command Reader 是有关联的 应该把它们放在一个工厂里面 这样子就是无法搭配的
	
    public Vector<EmployeeDO> getEmployees() {

        IDBConnection connection = dbConnectionFactory.createDBConnection();
        connection.setConnectionString("...");

        IDBCommand command = dbCommandFactory.createDBCommand();
        command.setCommandText("...");
        command.setConnection(connection);//关联性

        IDBDataReader reader = command.executeReader();//关联性
        while (reader.read()) {

        }

        return employeeDOs;
    }

}

IDBConnectionFactory,IDBCommandFactory,IDataReaderFactory三个工厂合并成一个工厂。 抽象工厂


//数据库访问有关的基类
class IDBConnection{

}

class IDBCommand{

}

class IDataReader{

}

//使用抽象工厂 前提 每一个方法创建出来的对象 互相之间是有关联的
//提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。
abstract class IDBFactory{
    public abstract IDBConnection createDBConnection();
    public abstract IDBCommand createDBCommand();
    public abstract IDataReader createDataReader();
    

}

//支持My SQL
class MySqlConnection extends IDBConnection{

}
class MySqlCommand extends IDBCommand{

 }
class MySqlDataReader extends IDataReader{

}


class MySqlDBFactory extends IDBFactory{

    @Override
    public IDBConnection createDBConnection() {
        return new MySqlConnection();
    }

    @Override
    public IDBCommand createDBCommand() {
        return new MySqlCommand();
    }

    @Override
    public IDataReader createDataReader() {
        return new MySqlDataReader();
    }


 }

//支持Oracle
class OracleConnection extends IDBConnection{

}

class OracleCommand extends IDBCommand{

}

class OracleDataReader extends IDataReader{

}

class OracleDBFactory extends IDBFactory{

    @Override
    public IDBConnection createDBConnection() {
        return new OracleConnection();
    }

    @Override
    public IDBCommand createDBCommand() {
        return new OracleCommand();
    }

    @Override
    public IDataReader createDataReader() {
        return new OracleDataReader();
    }
}


class EmployeeDAO{
    IDBFactory dbFactory;
    public Vector<EmployeeDO> getEmployees(){
        IDBConnection connection = dbConnectionFactory.createDBConnection();
        connection.setConnectionString("...");

        IDBCommand command = dbCommandFactory.createDBCommand();
        command.setCommandText("...");
        command.setConnection(connection);//关联性
        //经常面临着“一系列相互依赖的对象”的创建工作 上下一行就是
        IDBDataReader reader = command.executeReader();//关联性
        while (reader.read()) {


        }

        return employeeDOs;
    }



}

 由于需求的变化,往往存在更多系列对象的创建工作。比如代码中的 MySql是一个系列,Oracle是一个系列,DB2是一个系列。

类图结构中 AbstractFactory 对应代码中的 IDBFactory。CrateProductA() 对应的是 createDBConnection(),CrateProductB() 对应的是 createDBCommand()。ConcreteFactory1 对应的是 MySqlDBFactory,CrateProductA() 对应的是 createDBConnection(),CrateProductB() 对应的是 createDBCommand()。 ConcreteFactory2 对应的是 OracleDBFactory。

AbstractProductA 对应的是 IDBConnection,ProductA1 对应于 MySQLConnection,ProductA2 对应于 OracleConnection。

AbstractProductB 对应的是 IDBCommand,ProductA1 对应于 MySQLCommand,ProductA2 对应于 OracleCommand。

AbstractFactory,AbstractProductA ,AbstractProductB 是稳定的。

ConcreteFactory1 ,ConcreteFactory2 ,ProductA1 ,ProductA2 是变化的。

 要点总结

  如果没有应对“多系列对象构建’的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的工厂完全可以。
  “系列对象’指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列的对象之间不能相互依赖。
   Abstract Factory模式主要在于应对‘新系列”的需求变动。其缺点在于难以应对‘新对象’的需求变动。
 

Prototype 原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

主要解决:在运行期建立和删除原型。

何时使用: 1、当一个系统应该独立于它的产品创建,构成和表示时。 2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。 3、为了避免创建一个与产品类层次平行的工厂类层次时。 4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。

关键代码: 1、实现克隆操作,在 JAVA 继承 Cloneable,重写 clone(),在 .NET 中可以使用 Object 类的 MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。 2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。

应用实例: 1、细胞分裂。 2、JAVA 中的 Object clone() 方法。

优点: 1、性能提高。 2、逃避构造函数的约束。

缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。

使用场景: 1、资源优化场景。 2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 3、性能和安全要求的场景。 4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。 5、一个对象多个修改者的场景。 6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。 7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。

注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。

使用场景

在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。

模式定义

使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。

类图结构

使用工厂方法的代码作为例子

//抽象类
abstract class ISplitter{
    public abstract void split();

    public abstract ISplitter clone();

}
//具体类
class BinarySplitter extends ISplitter {

    @Override
    public void split() {

    }

    @Override
    public ISplitter clone() {
        BinarySplitter prototype= new BinarySplitter();
        //prototype.data=this.data;
        //...
        return prototype;
    }
}

class TxtSplitter extends ISplitter {

    @Override
    public void split() {

    }

    @Override
    public ISplitter clone() {
        TxtSplitter prototype= new TxtSplitter();
        //prototype.data=this.data;
        //...
        return prototype;
    }
}

class PictureSplitter extends ISplitter {

    @Override
    public void split() {

    }

    @Override
    public ISplitter clone() {
        PictureSplitter prototype= new PictureSplitter();
        //prototype.data=this.data;
        //...
        return prototype;
    }
}

class VideoSplitter extends ISplitter {

    @Override
    public void split() {

    }

    @Override
    public ISplitter clone() {
        VideoSplitter prototype= new VideoSplitter();
        //prototype.data=this.data;
        //...
        return prototype;
    }
}
class MainActivity extends Activity{

    ISplitter prototype;

    public MainActivity(ISplitter prototype){
        this.prototype=prototype;

    }

    public void buttonClick(){
        ISplitter splitter1=prototype.clone();//多态new
        splitter1.split();



        ISplitter splitter2=prototype.clone();//多态new
        splitter2.split();
    }
}

 类图结构中 prototype是稳定的。ConcretePrototype1和 ConcretePrototype2是具体的原型,是变化的。

在Android中原型模式的体现

Intent类中有clone()。

 要点总结

  Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有“稳定的接口”
  Prototype模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来做,它使得我们可以非常灵活地动态创建‘拥有某些稳定接口”的新对象一-所 需工作仅仅是注册一个新类的对象(即原型),然后在任何需要的地方Clone。
  Prototype模式中的Clone方法可以利用某些框架中的序列化来实现深拷贝。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值