最近我遇到了Null Object设计模式,我的同事说它可以用来取消整个代码中遇到的空指针检查.
例如,假设DAO类返回有关Customer的信息(在名为CustomerVO的值对象中).我的主要课程应该提取firstName和emailId并向客户发送电子邮件.
...
CustomerVO custVO = CustomerDAO.getCustomer(customerID);
if(custVO != null) { // imp, otherwise we may get null ptr exception in next line
sendEmail(custVO.getFirstName(), custVO.getEmailID());
}
...
Run Code Online (Sandbox Code Playgroud)
这是一个非常简单的示例,但是这样的空检查可以根据值对象的复杂性快速传播到整个代码中.
我有两个与null检查的问题, - 它们倾向于使代码变得丑陋且难以阅读 - 经验较少的开发人员在实际上应该抛出异常时进行不必要的空检查.例如,在上面的代码中,最好从getCustomer()本身抛出异常,因为如果它无法找到给定CustID的客户信息,则表明CustID无效.
好吧,回到null对象模式,我们可以使用'null'CustomerVO对象隐藏空检查吗?
CustomerVO {
String firstName = "";
String emailID = "";
}
Run Code Online (Sandbox Code Playgroud)
这不是有意义的.你怎么看?
为了最大限度地减少应用中的空值检查,您遵循了哪些内容.
我最近在Null对象设计模式上观看了这个youtube教程.即使它有一些错误:例如NullCar没有做任何事情会产生无限循环,这个概念得到了很好的解释.我的问题是,当可以为null的对象具有getter并在代码中使用时,您会怎么做?你怎么知道默认返回哪个值?或者我应该在所有对象中实现此模式?如果我需要返回字符串或基元怎么办?我是从Java角度谈论的.
编辑:我不会交易空对象测试默认值测试?如果没有,为什么不呢?
在我们的项目中,我们需要存储一些对象(例如User),并且User类必须有一个验证标志(setOutdated和isOutdated等方法)
有时,我们的User对象可能为null,但在这种情况下必须可以访问验证标志.可以从User类中提取这些方法,但由于语义的原因,该字段和方法必须位于该类中.
我发现了一些关于Null Object模式的文章(像这样),我想知道 - 是否可以创建Null Object(作为模式),它可以存储多个状态,如null过时,null不过时,不过时和过时不是没有过时的.
PS:如果在我的类中引入"过时"字段,则很难清除对象而不是将其设置为null
尽管在这里看到一些关于轨道中的Null对象的答案,我似乎无法让它们工作.
class User < ActiveRecord::Base
has_one :profile
accepts_nested_attributes_for :profile
def profile
self.profile || NullProfile #I have also tried
@profile || NullProfile #but it didn't work either
end
end
class NullProfile
def display #this method exists on the real Profile class
""
end
end
class UsersController < ApplicationController
def create
User.new(params)
end
end
Run Code Online (Sandbox Code Playgroud)
我的问题是在用户创建时,我为配置文件传递了适当的嵌套属性(profile_attributes),最后我的新用户使用了NullProfile.
我猜这意味着我的自定义配置文件方法在创建时被调用并返回NullProfile.我如何正确地执行此NullObject,以便这仅在读取时发生,而不是在对象的初始创建时发生.
对于Rails应用程序:是否存在用于命名映射到模型对象的空对象的命名约定?
例:
#app/models/blog.rb
class Blog < ActiveRecord::Base
end
#app/models/null_blog.rb
class NullBlog # Null Objects are POROs, correct?
def title
"No title"
end
end
# so to implement it I can do this:
blogs = ids.map{|id| Blog.find_by(id: id) || NullBlog.new}
# which allows me to do this and it works, even if some of those ids did not find a blog
blogs.each{|blog| blog.title}
Run Code Online (Sandbox Code Playgroud)
是NullBlog传统的吗?
无论这篇文章Avdi格林还是没有什么东西呈现由三弟梅斯提到的任何空对象命名约定。
我什至不确定我是否有问题,但我只是不喜欢我的 text_fields 和 text_areas 保存在数据库中而empty string不是nil.
我正在使用空对象模式,刚刚意识到如果我创建一个配置文件但不填写位置字段然后调用<%= @user.profile.location.upcase %>它就不会爆炸,因为位置是一个字符串,即使它是空的。
这是 Rails 的惯例吗?如果是这样,那为什么呢?这有点奇怪,因为假设个人number_of_pets资料上有一个 attr,然后我尝试调用类似的东西
<% if user.profile.number_of_pets.odd? %>
<%= @user.profile.first_name %> has odd number of pets
<% end %>
Run Code Online (Sandbox Code Playgroud)
然后事情就爆发了,因为我无法打电话nil.odd?。
形式如常,所以如果不填写,将保存为空字符串
<%= form_for @profile, url: user_profile_path do |f| %>
<%= f.label :city %>
<%= f.text_field :location, class: 'form-control' %>
......
Run Code Online (Sandbox Code Playgroud) 为什么Fowler PoEAA p.498以下列方式定义空对象模式(示例缩短,语言为c#但无关紧要):
public class Customer
{
public virtual string Name {get; set;}
}
public class NullCustomer : Customer, INull
{
public override Name
{
get { return "ImTheNull";}
// setter ommitted
}
}
Run Code Online (Sandbox Code Playgroud)
INull用作标记界面.我不喜欢这种方法有三个原因:
为什么不像这样实现:
public class Customer
{
public static readonly Customer NullCustomer = new Customer(){Name = "ImtTheNullCustomer";}
public string Name {get; set;}
}
Run Code Online (Sandbox Code Playgroud)
我一般都认为福勒的所有例子都经过深思熟虑,显然我必须在这里找到一些东西.
我在ASP.NET网站中主动使用缓存.
但是,db请求的某些对象确实不存在.例如,我Discount通过ProductId=@ProductId在ProductsDiscount表中查看记录来检查特定产品是否存在.没有记录意味着没有折扣.
你认为将null折扣对象放入缓存是一个好主意吗?
或者我会更好地发明一些东西(例如使用空对象模式).事实上,我真的不喜欢开始使用null-object模式的想法,因为它需要进行大量的重新设计,我现在至少要避免.
谢谢.欢迎任何想法.
PS实际上,当我尝试调用时,我甚至无法将null对象放入Cache中:
HttpContext.Current.Cache.Insert("name...", null);
Run Code Online (Sandbox Code Playgroud)
我收到:
值不能为空.
PPS为什么MSDN对此行为一无所知?
我正在尝试编写一个NullObject创建方法,在其中传入一个实现ICreateEmptyInstance接口(即为空)的类名,并且它遍历它的属性,寻找实现的其他类,ICreateEmptyInstance并将创建那些的"Null"实例.
public interface ICreateEmptyInstance { }
public static class NullObject
{
public static T Create<T>() where T : ICreateEmptyInstance, new()
{
var instance = new T();
var properties = typeof(T).GetProperties();
foreach (var property in properties.Where(property => typeof(ICreateEmptyInstance).IsAssignableFrom(property.PropertyType)))
{
var propertyInstance = NullObject.Create<property.PropertyType>();
property.SetValue(instance, propertyInstance);
}
return instance;
}
}
Run Code Online (Sandbox Code Playgroud)
我应该可以用它来称呼它
var myEmptyClass = NullObject.Create<MyClass>();
Run Code Online (Sandbox Code Playgroud)
我遇到问题的地方是在foreach循环中,有了这一行
var propertyInstance = NullObject.Create<property.PropertyType>();
Run Code Online (Sandbox Code Playgroud)
...显然这不起作用,但我怎样才能完成创建"空对象"以分配给我正在创建的实例.
编辑:那么泛型呢?我想创建空实例
foreach (var property in properties.Where(property => property.GetType().IsGenericType))
{
var propertyInstance = Enumerable.Empty<>(); //TODO: …Run Code Online (Sandbox Code Playgroud) 我有一个 Kotlin 数据类:
data class PaymentAccount(
val accountId: Int,
val accountNumber: String,
val title: String
)
Run Code Online (Sandbox Code Playgroud)
这就是我在 Java 中所做的:
创建一个抽象类:
public abstract class PaymentAccount {
protected int accountId;
protected String accountNumber;
protected String title;
public PaymentAccount(int accountId,
String accountNumber,
String title) {
this.accountId = accountId;
this.accountNumber = accountNumber;
this.title = title;
}
}
Run Code Online (Sandbox Code Playgroud)
创建空对象并扩展抽象类:
public class NullPaymentAccount extends PaymentAccount {
public NullPaymentAccount() {
super(-1,
"Invalid account number",
"Invalid title");
}
}
Run Code Online (Sandbox Code Playgroud)
创建一个真实的对象并扩展抽象类:
public class RealPaymentAccount extends PaymentAccount {
public RealPaymentAccount(int …Run Code Online (Sandbox Code Playgroud) 我发现这个问题以某种方式在 Kotlin 中实现了空对象模式。我通常在 Java 中做一些不同的事情:
class MyClass {
static final MyClass INVALID = new MyClass();
public MyClass() {
// empty
}
}
Run Code Online (Sandbox Code Playgroud)
这样,我就可以随时将MyClass.INVALID其用作空对象。
如何在 Kotlin 中实现这种风格?
我摆弄了这样的事情:
data class MyClass(val id: Int) {
object INVALID: MyClass {
}
}
Run Code Online (Sandbox Code Playgroud)
但这甚至无法编译。
使用Null Object模式时,如果情况无效,您将如何"检查"?例如,当存储库中找不到任何项目时,向用户显示"未找到"消息.
我必须做一个美化的空检查吗?
这些技术似乎打败了Null Object模式本身的目的