设计模式系列 - 创建型模式

单例模式

懒汉式,线程不安全。

除非是单线程程序,否则不推荐使用。

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

饿汉式,线程安全

当程序总是使用这个类的实例时,或者在资源和时间方面创建实例的成本不太大时,可以使用它。
可能导致资源浪费。因为类的实例总是被创建的,不管它是否必需。在创建实例时也会浪费CPU时间。
无法处理异常。

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

静态块,线程安全

对象是在静态块中创建的,这样我们就可以访问它的创建,比如异常处理。同样地,对象也是在类加载时创建的。
当在创建具有紧急初始化的对象时可能出现异常时,可以使用它。可能导致资源浪费。因为类的实例总是被创建的,不管它是否必需。

public class Singleton  
{ 
  // public instance 
  public static Singleton instance; 
  
  private Singleton()  
  { 
    // private constructor 
  } 
  
  { 
    // static block to initialize instance 
    instance = new Singleton(); 
  } 
}

同步方式,线程安全

会导致性能下降

public class Singleton  
{ 
  // private instance, so that it can be 
  // accessed by only by getInstance() method 
  private static Singleton instance; 
  
  private Singleton()  
  { 
    // private constructor 
  } 
  
 //synchronized method to control simultaneous access 
  synchronized public static Singleton getInstance()  
  { 
    if (instance == null)  
    { 
      // if instance is null, initialize 
      instance = new Singleton(); 
    } 
    return instance; 
  } 
} 

双检方式,线程安全

克服了同步代码的开销问题。延迟初始化,可以用于高性能的多线程应用。

public class Singleton  
{ 
  // private instance, so that it can be 
  // accessed by only by getInstance() method 
  private static Singleton instance; 
  
  private Singleton()  
  { 
    // private constructor 
  } 
  
  public static Singleton getInstance() 
  { 
    if (instance == null)  
    { 
      //synchronized block to remove overhead 
      synchronized (Singleton.class) 
      { 
        if(instance==null) 
        { 
          // if instance is null, initialize 
          instance = new Singleton(); 
        } 
        
      } 
    } 
    return instance; 
  } 
} 

内部静态类方案,优方案

加载单例类时,不会加载内部类,因此在加载类时不会创建对象。只有在调用getInstance()方法时才创建内部类。它是懒惰的初始化。
这是最广泛使用的方法,因为它不使用同步,性能更好。

public class Singleton  
{ 
  
  private Singleton()  
  { 
    // private constructor 
  } 
  
  // Inner class to provide instance of class 
  private static class BillPughSingleton 
  { 
    private static final Singleton INSTANCE = new Singleton(); 
  } 
  
  public static Singleton getInstance()  
  { 
    return BillPughSingleton.INSTANCE; 
  } 
} 

枚举,优方案

自动支持序列化机制,绝对防止多次实例化。这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}

工厂方法

是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

//定义车类
public enum CarType {
    SMALL, SEDAN, LUXURY
}

//车的基类
public abstract class Car {
 
    public Car(CarType model) {
        this.model = model;
        arrangeParts();
    }
 
    private void arrangeParts() {
        // Do one time processing here
    }
 
    // Do subclass level processing in this method
    protected abstract void construct();
 
    private CarType model = null;
 
    public CarType getModel() {
        return model;
    }
 
    public void setModel(CarType model) {
        this.model = model;
    }
}
//豪华车
public class LuxuryCar extends Car {
 
    LuxuryCar() {
        super(CarType.LUXURY);
        construct();
    }
 
    @Override
    protected void construct() {
        System.out.println("Building luxury car");
        // add accessories
    }
}

public class SmallCar extends Car {
 
    SmallCar() {
        super(CarType.SMALL);
        construct();
    }
 
    @Override
    protected void construct() {
        System.out.println("Building small car");
        // add accessories
    }
}

public class SedanCar extends Car {
 
    SedanCar() {
        super(CarType.SEDAN);
        construct();
    }
 
    @Override
    protected void construct() {
        System.out.println("Building sedan car");
        // add accessories
    }
}

public class CarFactory {
    public static Car buildCar(CarType model) {
        Car car = null;
        switch (model) {
        case SMALL:
            car = new SmallCar();
            break;
 
        case SEDAN:
            car = new SedanCar();
            break;
 
        case LUXURY:
            car = new LuxuryCar();
            break;
 
        default:
            // throw some exception
            break;
        }
        return car;
    }
}

public class TestFactoryPattern {
    public static void main(String[] args) {
        System.out.println(CarFactory.buildCar(CarType.SMALL));
        System.out.println(CarFactory.buildCar(CarType.SEDAN));
        System.out.println(CarFactory.buildCar(CarType.LUXURY));
    }
}

 

抽象工厂

围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
我们重用上一节的CarType

public abstract class Car {

  public Car(CarType model, Location location){
    this.model = model;
    this.location = location;
  }

  protected abstract void construct();

  private CarType model = null;
  private Location location = null;

  //getters and setters

  @Override
  public String toString() {
    return "Model- "+model + " built in "+location;
  }
}

public enum Location {
  DEFAULT, USA, ASIA
}

public class LuxuryCar extends Car
{
  public LuxuryCar(Location location)
  {
    super(CarType.LUXURY, location);
    construct();
  }

  @Override
  protected void construct() {
    System.out.println("Building luxury car");
    //add accessories
  }
}

public class AsiaCarFactory
{
  public static Car buildCar(CarType model)
  {
    Car car = null;
    switch (model)
    {
      case SMALL:
      car = new SmallCar(Location.ASIA);
      break;

      case SEDAN:
      car = new SedanCar(Location.ASIA);
      break;

      case LUXURY:
      car = new LuxuryCar(Location.ASIA);
      break;

      default:
      //throw some exception
      break;
    }
    return car;
  }
}

public class DefaultCarFactory
{
  public static Car buildCar(CarType model)
  {
    Car car = null;
    switch (model)
    {
      case SMALL:
      car = new SmallCar(Location.DEFAULT);
      break;

      case SEDAN:
      car = new SedanCar(Location.DEFAULT);
      break;

      case LUXURY:
      car = new LuxuryCar(Location.DEFAULT);
      break;

      default:
      //throw some exception
      break;
    }
    return car;
  }
}

public class USACarFactory
{
  public static Car buildCar(CarType model)
  {
    Car car = null;
    switch (model)
    {
      case SMALL:
      car = new SmallCar(Location.USA);
      break;

      case SEDAN:
      car = new SedanCar(Location.USA);
      break;

      case LUXURY:
      car = new LuxuryCar(Location.USA);
      break;

      default:
      //throw some exception
      break;
    }
  return car;
  }
}

public class CarFactory
{
  private CarFactory() {
    //Prevent instantiation
  }
 
  public static Car buildCar(CarType type,Location location)
  {
    Car car = null;
    //Use location specific car factory
    switch(location)
    {
      case USA:
        car = USACarFactory.buildCar(type);
        break;
      case ASIA:
        car = AsiaCarFactory.buildCar(type);
        break;
      default:
        car = DefaultCarFactory.buildCar(type);
    }
  return car;
  }
}

public class TestFactoryPattern
{
  public static void main(String[] args)
  {
    System.out.println(CarFactory.buildCar(CarType.SMALL,Location.USA));
    System.out.println(CarFactory.buildCar(CarType.SEDAN,Location.USA));
    System.out.println(CarFactory.buildCar(CarType.LUXURY,Location.ASIA));
  }
}

这两个工厂模式的代码还有很多switch,仅仅是演示而已

建造者模式

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

interface HousePlan 
{ 
    public void setBasement(String basement); 

    public void setStructure(String structure); 

    public void setRoof(String roof); 

    public void setInterior(String interior); 
} 

class House implements HousePlan 
{ 

    private String basement; 
    private String structure; 
    private String roof; 
    private String interior; 

    public void setBasement(String basement) 
    { 
        this.basement = basement; 
    } 

    public void setStructure(String structure) 
    { 
        this.structure = structure; 
    } 

    public void setRoof(String roof) 
    { 
        this.roof = roof; 
    } 

    public void setInterior(String interior) 
    { 
        this.interior = interior; 
    } 

} 


interface HouseBuilder 
{ 

    public void buildBasement(); 

    public void buildStructure(); 

    public void bulidRoof(); 

    public void buildInterior(); 

    public House getHouse(); 
} 

class IglooHouseBuilder implements HouseBuilder 
{ 
    private House house; 

    public IglooHouseBuilder() 
    { 
        this.house = new House(); 
    } 

    public void buildBasement() 
    { 
        house.setBasement("Ice Bars"); 
    } 

    public void buildStructure() 
    { 
        house.setStructure("Ice Blocks"); 
    } 

    public void buildInterior() 
    { 
        house.setInterior("Ice Carvings"); 
    } 

    public void bulidRoof() 
    { 
        house.setRoof("Ice Dome"); 
    } 

    public House getHouse() 
    { 
        return this.house; 
    } 
} 

class TipiHouseBuilder implements HouseBuilder 
{ 
    private House house; 

    public TipiHouseBuilder() 
    { 
        this.house = new House(); 
    } 

    public void buildBasement() 
    { 
        house.setBasement("Wooden Poles"); 
    } 

    public void buildStructure() 
    { 
        house.setStructure("Wood and Ice"); 
    } 

    public void buildInterior() 
    { 
        house.setInterior("Fire Wood"); 
    } 

    public void bulidRoof() 
    { 
        house.setRoof("Wood, caribou and seal skins"); 
    } 

    public House getHouse() 
    { 
        return this.house; 
    } 

} 

class CivilEngineer 
{ 

    private HouseBuilder houseBuilder; 

    public CivilEngineer(HouseBuilder houseBuilder) 
    { 
        this.houseBuilder = houseBuilder; 
    } 

    public House getHouse() 
    { 
        return this.houseBuilder.getHouse(); 
    } 

    public void constructHouse() 
    { 
        this.houseBuilder.buildBasement(); 
        this.houseBuilder.buildStructure(); 
        this.houseBuilder.bulidRoof(); 
        this.houseBuilder.buildInterior(); 
    } 
} 

class Builder 
{ 
    public static void main(String[] args) 
    { 
        HouseBuilder iglooBuilder = new IglooHouseBuilder(); 
        CivilEngineer engineer = new CivilEngineer(iglooBuilder); 

        engineer.constructHouse(); 

        House house = engineer.getHouse(); 

        System.out.println("Builder constructed: "+ house); 
    } 
} 

以上是做分部建造,还可以避免new product的过多参数,比如:

public User (String firstName, String lastName, int age, String phone){ ... }
public User (String firstName, String lastName, String phone, String address){ ... }
public User (String firstName, String lastName, int age){ ... }
public User (String firstName, String lastName){ ... }

如果再多十几个属性怎么办?

public class User 
{
    //All final attributes
    private final String firstName; // required
    private final String lastName; // required
    private final int age; // optional
    private final String phone; // optional
    private final String address; // optional
 
    private User(UserBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
    }
 
    //All getter, and NO setter to provde immutability
    public String getFirstName() {
        return firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public int getAge() {
        return age;
    }
    public String getPhone() {
        return phone;
    }
    public String getAddress() {
        return address;
    }
 
    @Override
    public String toString() {
        return "User: "+this.firstName+", "+this.lastName+", "+this.age+", "+this.phone+", "+this.address;
    }
 
    public static class UserBuilder 
    {
        private final String firstName;
        private final String lastName;
        private int age;
        private String phone;
        private String address;
 
        public UserBuilder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }
        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }
        public UserBuilder address(String address) {
            this.address = address;
            return this;
        }
        //Return the finally consrcuted User object
        public User build() {
            User user =  new User(this);
            validateUserObject(user);
            return user;
        }
        private void validateUserObject(User user) {
            //Do some basic validations to check 
            //if user object does not break any assumption of system
        }
    }
}

public static void main(String[] args) {
    User user1 = new User.UserBuilder("Lokesh", "Gupta")
    .age(30)
    .phone("1234567")
    .address("Fake address 1234")
    .build();
 
    System.out.println(user1);
 
    User user2 = new User.UserBuilder("Jack", "Reacher")
    .age(40)
    .phone("5655")
    //no address
    .build();
 
    System.out.println(user2);
 
    User user3 = new User.UserBuilder("Super", "Man")
    //No age
    //No phone
    //no address
    .build();
 
    System.out.println(user3);
}

 

原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。原型设计模式用于应用程序需要创建一个类的多个实例的场景中,这些实例几乎具有相同的状态或差别非常小。
在这个设计模式中,实际对象的一个实例(即prototype)是在启动时创建的,然后每当需要新实例时,就克隆这个原型以拥有另一个实例。这种模式的主要优点是具有最小的实例创建过程
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

public interface PrototypeCapable extends Cloneable
{
    public PrototypeCapable clone() throws CloneNotSupportedException;
}

public class Movie implements PrototypeCapable
{
    private String name = null;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public Movie clone() throws CloneNotSupportedException {
        System.out.println("Cloning Movie object..");
        return (Movie) super.clone();
    }
    @Override
    public String toString() {
        return "Movie";
    }
}
 
public class Album implements PrototypeCapable
{
    private String name = null;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public Album clone() throws CloneNotSupportedException {
        System.out.println("Cloning Album object..");
        return (Album) super.clone();
    }
    @Override
    public String toString() {
        return "Album";
    }
}
 
public class Show implements PrototypeCapable
{
    private String name = null;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public Show clone() throws CloneNotSupportedException {
        System.out.println("Cloning Show object..");
        return (Show) super.clone();
    }
    @Override
    public String toString() {
        return "Show";
    }
}

public class PrototypeCache
{
    public static class ModelType
    {
        public static final String MOVIE = "movie";
        public static final String ALBUM = "album";
        public static final String SHOW = "show";
    }
    private static java.util.Map<String , PrototypeCapable> prototypes = new java.util.HashMap<String , PrototypeCapable>();
 
    static
    {
        prototypes.put(ModelType.MOVIE, new Movie());
        prototypes.put(ModelType.ALBUM, new Album());
        prototypes.put(ModelType.SHOW, new Show());
    }
 
    public static PrototypeCapable getInstance(final String s) throws CloneNotSupportedException {
        return ((PrototypeCapable) prototypes.get(s)).clone();
    }
}
TestPrototypePattern
public class TestPrototypePattern
{
    public static void main(String[] args)
    {
        try
        {
            String moviePrototype  = PrototypeCache.getInstance(ModelType.MOVIE).toString();
            System.out.println(moviePrototype);
 
            String albumPrototype  = PrototypeCache.getInstance(ModelType.ALBUM).toString();
            System.out.println(albumPrototype);
 
            String showPrototype  = PrototypeCache.getInstance(ModelType.SHOW).toString();
            System.out.println(showPrototype);
 
        }
        catch (CloneNotSupportedException e)
        {
            e.printStackTrace();
        }
    }
}

 

Singleton
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分类,并根据分类结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值