第七天----创建型设计模式笔记

笔记参考文章

1、创建型模式(Creational Pattern)

对类的实例化过程进行了抽象,
能够将软件模块中对象的创建和对象的使用分离。
为了使软件的结构更加清晰,
外界对于这些对象只需要知道它们共同的接口
而不清楚其具体的实现细节,
使整个系统的设计更加符合单一职责原则。

创建型模式隐藏了类的实例的创建细节
通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。

包含模式
简单工厂模式(Simple Factory)
工厂方法模式(Factory Method)
抽象工厂模式(Abstract Factory)
建造者模式(Builder)
原型模式(Prototype)
单例模式(Singleton)

2、简单工厂模式(Simple Factory Pattern)

又称为静态工厂方法(Static Factory Method)模式,
它属于类创建型模式。
可以根据参数的不同返回不同类的实例。
简单工厂模式专门定义一个类来负责创建其他类的实例,
被创建的实例通常都具有共同的父类。

----简单工厂模式包含如下角色:
Factory:工厂角色
工厂角色负责实现创建所有实例的内部逻辑
Product:抽象产品角色
抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
ConcreteProduct:具体产品角色
具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

----以登录功能来说,
假如应用系统需要支持多种登录方式如:口令认证、域认证
(口令认证通常是去数据库中验证用户,而域认证则是需要到微软的域中验证用户)。
那么自然的做法就是建立一个各种登录方式都适用的接口

//抽象产品Login
public interface Login {
    //登录验证
    public boolean verify(String name , String password);
}

//具体产品DomainLogin
public class DomainLogin implements Login {

    @Override
    public boolean verify(String name, String password) {
        // TODO Auto-generated method stub
        /**
         * 业务逻辑
         */
        return true;
    }
}

//具体产品PasswordLogin
public class PasswordLogin implements Login {

    @Override
    public boolean verify(String name, String password) {
        // TODO Auto-generated method stub
        /**
         * 业务逻辑
         */
        return true;
    }
}

//工厂类LoginManager
//根据调用者不同的要求,创建出不同的登录对象并返回。而如果碰到不合法的要求,会返回一个Runtime异常。
public class LoginManager {
    public static Login factory(String type){
        if(type.equals("password")){

            return new PasswordLogin();

        }else if(type.equals("passcode")){

            return new DomainLogin();

        }else{
            /**
             * 这里抛出一个自定义异常会更恰当
             */
            throw new RuntimeException("没有找到登录类型");
        }
    }
}

//测试调用
public class Test {
    public static void main(String[] args) {
        String loginType = "password";
        String name = "name";
        String password = "password";
        Login login = LoginManager.factory(loginType);
        boolean bool = login.verify(name, password);
        if (bool) {
            /**
             * 业务逻辑
             */
        } else {
            /**
             * 业务逻辑
             */
        }
    }
}

3、工厂方法模式(Factory Method Pattern)

又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式
或者多态工厂(Polymorphic Factory)模式,
它属于类创建型模式。
工厂父类负责定义创建产品对象的公共接口,
而工厂子类则负责生成具体的产品对象,
这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,
即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

----工厂方法模式包含如下角色:
1.Product:抽象产品,工厂方法模式所创建的对象的超类,
也就是所有产品类的共同父类或共同拥有的接口。
在实际的系统中,这个角色也常常使用抽象类实现。
2.ConcreteProduct:具体产品,
这个角色实现了抽象产品(Product)所声明的接口,
工厂方法模式所创建的每一个对象都是某个具体产品的实例。
3.Factory:抽象工厂,担任这个角色的是工厂方法模式的核心,
任何在模式中创建对象的工厂类必须实现这个接口。
在实际的系统中,这个角色也常常使用抽象类实现。
4.ConcreteFactory:具体工厂,担任这个角色的是实现了抽象工厂接口的具体Java类。
具体工厂角色含有与业务密切相关的逻辑,
并且受到使用者的调用以创建具体产品对象。

----在灯这个品类下,有灯泡和灯管两种产品,
并且都实现了灯的通用方法:关灯和开灯。
在工厂类下,有各种生产具体产品的子工厂负责生产相应的两种灯具。

//抽象的产品接口ILight
public interface ILight
{
    void TurnOn();
    void TurnOff();
}

//具体的产品类:BulbLight
public class BulbLight implements ILight
{
    public void TurnOn()
    {
        Console.WriteLine("BulbLight turns on.");
    }
    public void TurnOff()
    {
        Console.WriteLine("BulbLight turns off.");
    }
}

//具体的产品类:TubeLight
public class TubeLight implements ILight
{
    public void TurnOn()
    {
        Console.WriteLine("TubeLight turns on.");
    }

    public void TurnOff()
    {
        Console.WriteLine("TubeLight turns off.");
    }

}

//抽象的工厂类
public interface ICreator
{
    ILight CreateLight();
}

//具体的工厂类:BulbCreator
public class BulbCreator implements ICreator
{
    public ILight CreateLight()
    {
        return new BulbLight();
    }

}

//具体的工厂类:TubeCreator
public class TubeCreator implements ICreator
{
    public ILight CreateLight()
    {
        return new TubeLight();
    }
}

//客户端调用
static void Main(string[] args)
{
    //先给我来个灯泡
    ICreator creator = new BulbCreator();
    ILight light = creator.CreateLight();
    light.TurnOn();
    light.TurnOff();

    //再来个灯管看看
    creator = new TubeCreator();
    light = creator.CreateLight();
    light.TurnOn();
    light.TurnOff();

}

4、抽象工厂模式(Abstract Factory Pattern)

提供一个创建一系列相关或相互依赖对象的接口,
而无须指定它们具体的类。
抽象工厂模式又称为Kit模式,
属于对象创建型模式。

----抽象工厂模式包含如下角色:
AbstractFactory:抽象工厂
ConcreteFactory:具体工厂
AbstractProduct:抽象产品
Product:具体产品

----假设有一个移动终端工厂,
可以制造苹果系列的移动产品和三星系列的移动产品。
这个工厂下有两个子厂,
一个负责制造苹果系列的Pad和三星系列的Pad,
另一个负责制造苹果系列的手机和三星系列的手机。
这便是一个典型的抽象工厂的实例。


//抽象产品: 苹果系列
public interface Apple
{
    void AppleStyle();
}

//抽象产品: 三星系列
public interface Sumsung
{
    void BangziStyle();
}

//具体产品:iphone
public class iphone implements Apple
{
    public void AppleStyle()
    {
        Console.WriteLine("Apple's style: iPhone!");
    }
}

//具体产品:ipad
public class ipad implements Apple
{
    public void AppleStyle()
    {
        Console.WriteLine("Apple's style: iPad!");
    }
}

//具体产品:note2
public class note2 implements Sumsung
{
    public void BangziStyle()
    {
        Console.WriteLine("Bangzi's style : Note2!");
    }
}

//具体产品:tabs
public class Tabs implements Sumsung
{
    public void BangziStyle()
    {
        Console.WriteLine("Bangzi's style : Tab!");
    }
}

//抽象工厂
public interface Factory
{
    Apple createAppleProduct();
    Sumsung createSumsungProduct();
}

//手机工厂
public class Factory_Phone implements Factory
{
    public Apple createAppleProduct()
    {
        return new iphone();
    }

    public Sumsung createSumsungProduct()
    {
        return new note2();
    }
}

//pad工厂
public class Factory_Pad implements  Factory
{
    public Apple createAppleProduct()
    {
        return new ipad();
    }

    public Sumsung createSumsungProduct()
    {
        return new Tabs();
    }
}

//客户端调用
public static void Main(string[] args)
{
    //采购商要一台iPad和一台Tab
    Factory factory = new Factory_Pad();
    Apple apple = factory.createAppleProduct();
    apple.AppleStyle();
    Sumsung sumsung = factory.createSumsungProduct();
    sumsung.BangziStyle();

    //采购商又要一台iPhone和一台Note2
    factory = new Factory_Phone();
    apple = factory.createAppleProduct();
    apple.AppleStyle();
    sumsung = factory.createSumsungProduct();
    sumsung.BangziStyle();
    Console.ReadKey();
}

5、单例模式

作为对象的创建模式,
单例模式确保某一个类只有一个实例,
而且自行实例化并向整个系统提供这个实例。

1.懒汉式,线程不安全
懒汉式其实是一种比较形象的称谓。既然懒,
那么在创建对象实例的时候就不着急。
会一直等到马上要使用对象实例的时候才会创建,
因此在装载对象的时候不创建对象实例。

public class Singleton {
    private static Singleton instance;
    private Singleton (){}

    public static Singleton getInstance() {
     if (instance == null) {
         instance = new Singleton();
     }
     return instance;
    }
}

这段代码存在致命的问题。
当有多个线程并行调用 getInstance() 的时候,
就会创建多个实例。
也就是说在多线程下不能正常工作。

2.懒汉式,线程安全
为了解决上面的问题,
最简单的方法是将整个 getInstance() 方法设为同步(synchronized)。

public static synchronized Singleton getInstance() {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}

虽然做到了线程安全,
并且解决了多实例的问题,但是它并不高效。
因为在任何时候只能有一个线程调用 getInstance() 方法。
但是同步操作只需要在第一次调用时才被需要,
即第一次创建单例实例对象时。
这就引出了双重检验锁。

3.双重检验锁
双重检验锁模式(double checked locking pattern),
是一种使用同步块加锁的方法。
程序员称其为双重检查锁,
因为会有两次检查 instance == null,
一次是在同步块外,一次是在同步块内。
为什么在同步块内还要再检验一次?
因为可能会有多个线程一起进入同步块外的 if,
如果在同步块内不进行二次检验的话就会生成多个实例了。

public static Singleton getSingleton() {
    if (instance == null) {                         //Single Checked
        synchronized (Singleton.class) {
            if (instance == null) {                 //Double Checked
                instance = new Singleton();
            }
        }
    }
    return instance ;
}

instance = new Singleton()这句并非是一个原子操作,
事实上在 JVM 中这句话大概做了下面 3 件事情:
1).给 instance 分配内存
2).调用 Singleton 的构造函数来初始化成员变量
3).将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)。
但是在 JVM 的即时编译器中存在指令重排序的优化。
也就是说上面的第二步和第三步的顺序是不能保证的
,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。
如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,
这时 instance 已经是非 null 了(但却没有初始化),
所以线程二会直接返回 instance,
然后使用,然后顺理成章地报错。
只需要将 instance 变量声明成 volatile 就可以了。

public class Singleton {
    private volatile static Singleton instance; //声明成 volatile
    private Singleton (){}

    public static Singleton getSingleton() {
        if (instance == null) {                         
            synchronized (Singleton.class) {
                if (instance == null) {       
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

}

4.饿汉式 static final field
饿汉式其实是一种比较形象的称谓。
既然饿,那么在创建对象实例的时候就比较着急
于是在装载类的时候就创建对象实例。
这种方法非常简单,因为单例的实例被声明成 static 和 final 变量了,
在第一次加载类到内存中时就会初始化,所以创建实例本身是线程安全的。

public class Singleton{
    //类加载时就初始化
    private static final Singleton instance = new Singleton();

    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
}

缺点是它不是一种懒加载模式(lazy initialization),
单例会在加载类后一开始就被初始化,
即使客户端没有调用 getInstance()方法。

饿汉式的创建方式在一些场景中将无法使用:
譬如 Singleton 实例的创建是依赖参数或者配置文件的,
在 getInstance() 之前必须调用某个方法设置参数给它,
那样这种单例写法就无法使用了。

5.静态内部类 static nested class
这种方法也是《Effective Java》上所推荐的。

public class Singleton {  
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE; 
    }  
}

这种写法仍然使用JVM本身机制保证了线程安全问题。
由于静态单例对象没有作为Singleton的成员变量直接实例化,
因此类加载时不会实例化Singleton,
第一次调用getInstance()时将加载内部类SingletonHolder,
在该内部类中定义了一个static类型的变量INSTANCE ,
此时会首先初始化这个成员变量,
由Java虚拟机来保证其线程安全性,
确保该成员变量只能初始化一次。
由于getInstance()方法没有任何线程锁定,
因此其性能不会造成任何影响。
由于 SingletonHolder 是私有的,
除了 getInstance() 之外没有办法访问它,因此它是懒汉式的;
同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖 JDK 版本。

6.枚举 Enum

public enum EasySingleton{
    INSTANCE;
}

可以通过EasySingleton.INSTANCE来访问实例,
这比调用getInstance()方法简单多了。
创建枚举默认就是线程安全的,
所以不需要担心double checked locking,
而且还能防止反序列化导致重新创建新的对象。

6、建造者模式(Builder Pattern)

又可以称为生成器模式。
将一个复杂对象的构建与它的表示分离,
使得同样的构建过程可以创建不同的表示。
建造者模式是一步一步创建一个复杂的对象
,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,
用户不需要知道内部的具体构建细节。
建造者模式属于对象创建型模式。

----建造者模式包含如下角色:
Builder:抽象建造者
ConcreteBuilder:具体建造者
Director:指挥者
Product:产品角色

----在Android源码中最常用到的Builder模式就是AlertDialog.Builder,
使用该Builder来构建复杂的AlertDialog对象。
简单示例如下 :

//显示基本的AlertDialog  
private void showDialog(Context context) {  
    AlertDialog.Builder builder = new AlertDialog.Builder(context);  
    builder.setIcon(R.drawable.icon);  
    builder.setTitle("Title");  
    builder.setMessage("Message");  
    builder.setPositiveButton("Button1",  
            new DialogInterface.OnClickListener() {  
                public void onClick(DialogInterface dialog, int whichButton) {  
                    setTitle("点击了对话框上的Button1");  
                }  
            });  
    builder.setNeutralButton("Button2",  
            new DialogInterface.OnClickListener() {  
                public void onClick(DialogInterface dialog, int whichButton) {  
                    setTitle("点击了对话框上的Button2");  
                }  
            });  
    builder.setNegativeButton("Button3",  
            new DialogInterface.OnClickListener() {  
                public void onClick(DialogInterface dialog, int whichButton) {  
                    setTitle("点击了对话框上的Button3");  
                }  
            });  
    builder.create().show();  // 构建AlertDialog, 并且显示
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值