Эффективный Java Joshua Bloch описывает разработчика Pattern, который может использоваться для создания объектов с несколькими дополнительно настраиваемыми параметрами. Соглашение о присвоении имен, которое он предлагает для функций Разработчика, который "моделирует названные дополнительные параметры, как найдено в Ada и Python", кажется, не падает в соответствии со стандартным соглашением о присвоении имен Java. Функции Java имеют тенденцию полагаться на наличие глагола для запуска функции и затем основанной на существительном фразы для описания то, что это делает. Класс Разработчика только имеет название переменной, это должно быть определено той функцией.
Есть ли какие-либо API в библиотеках стандарта Java, который использует разработчика Pattern? Я хочу сравнить предложения в книге к фактической реализации в базовом наборе библиотек Java прежде, чем преследовать его использование.
Я не уверен насчет внутри ядра JDK, но хорошие примеры можно найти в Guava. MapMaker
, наверное, лучший пример, о котором я могу подумать. Например, из документации:
ConcurrentMap<Key, Graph> graphs = new MapMaker()
.concurrencyLevel(32)
.softKeys()
.weakValues()
.expiration(30, TimeUnit.MINUTES)
.makeComputingMap(
new Function<Key, Graph>() {
public Graph apply(Key key) {
return createExpensiveGraph(key);
}
});
Да, такие вещи могут идти против зерна "стандартного" Java-именования, но они также могут быть очень читабельными.
Для ситуаций, когда вы не возвращаете "this", а новый объект (обычно с неизменяемыми типами), мне нравится префикс "с" - Joda Time широко использует этот паттерн. Это не шаблон конструктора, а альтернативная и связанная с ним форма построения.
Можно проверить значение null, а затем сохранить DBNull.Value в качестве значения. Существует статья MSDN о нулевых значениях , в которой конкретно указывается на отсутствие поддержки NULL < > наборами данных.
Там, где у вас есть
values[i] = props[i].GetValue(item, null);
сделать его
var value = props[i].GetValue(item, null);
values[i] = value ?? ((object)DBNull.Value);
-121--4950640- Поскольку, кажется, существует много путаницы в отношении работы стековых кадров и методов, вот простая демонстрация:
static void Main(string[] args)
{
MyClass c = new MyClass();
c.Name = "MyTest";
Console.ReadLine();
}
class MyClass
{
private string name;
void TestMethod()
{
StackTrace st = new StackTrace();
StackFrame currentFrame = st.GetFrame(1);
MethodBase method = currentFrame.GetMethod();
Console.WriteLine(method.Name);
}
public string Name
{
get { return name; }
set
{
TestMethod();
name = value;
}
}
}
Результатом этой программы будет:
set _ Name
Свойства в C # являются формой синтаксического сахара. Они компилируются до методов getter и setter в IL, и возможно, что некоторые языки .NET даже не распознают их как свойства - Разрешение собственности делается полностью по конвенции, нет на самом деле никаких правил в спецификации IL.
Теперь, скажем на данный момент, у вас была действительно веская причина для программы, чтобы захотеть изучить свой собственный стек (и есть драгоценные мало практических причин для этого). Почему в мире вы хотите, чтобы он вел себя по-разному для свойств и методов?
Все обоснование атрибутов состоит в том, что они являются своего рода метаданными. Если требуется другое поведение, закодируйте его в атрибут . Если атрибут может означать две разные вещи в зависимости от того, применен ли он к методу или свойству - тогда у вас должно быть два атрибута . Установите для первого целевого объекта значение AttribureTargets.Method
, а для второго - значение AttribureTargets.Property
. Просто.
Но опять же, в лучшем случае опасно ходить по собственной стопке, чтобы забрать некоторые атрибуты из метода вызова. В путь, вы замораживаете дизайн вашей программы, что значительно затрудняет для кого-либо расширение или рефактор. Это не тот способ, которым атрибуты обычно используются. Более подходящим примером может быть что-то вроде атрибута валидации:
public class Customer
{
[Required]
public string Name { get; set; }
}
Тогда ваш код валидатора, который ничего не знает о фактически передаваемой сущности, может сделать это:
public void Validate(object o)
{
Type t = o.GetType();
foreach (var prop in
t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (Attribute.IsDefined(prop, typeof(RequiredAttribute)))
{
object value = prop.GetValue(o, null);
if (value == null)
throw new RequiredFieldException(prop.Name);
}
}
}
Другими словами, вы изучаете атрибуты экземпляра , который был вам предоставлен , но который вы не обязательно знаете ничего о типе. XML-атрибуты, атрибуты контракта данных, даже атрибуты атрибутов - почти все атрибуты в .NET Framework используются таким образом для реализации некоторых функций, которые являются динамическими в отношении типа экземпляра , но не в отношении состояния программы или того, что происходит в стеке. Очень маловероятно, что вы действительно контролируете это в точке, где вы создаете трассировку стека.
Поэтому я еще раз рекомендую вам не использовать подход stack-walking, если у вас нет очень веских причин сделать это, о чем вы еще не сказали нам. В противном случае вы, вероятно, окажетесь в мире боли.
Если вы абсолютно обязаны (не говорите, что мы не предупреждали вас), то используйте два атрибута,один, который может применяться к методам, и один, который может применяться к свойствам. Я думаю, вы найдете это гораздо проще, чем один супер-атрибут.
-121--1009586-Он определен (не реализован) только в стандартной библиотеке, однако объекты источника данных JDBC напоминают мне о образце построителя. Создается объект источника данных, затем задается ряд свойств, а затем устанавливается соединение.
Вот пример кода...
DataSource ds = (DataSource)ctx.lookup("jdbc/AcmeDB");
ds.setServerName("my_database_server");
ds.setDescription("the data source for inventory and personnel");
Connection con = ds.getConnection("genius", "abracadabra");
ProcessBuilder в значительной степени является экземпляром шаблона построителя, но не совсем использует соглашения об именах Java.
ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2"); Map env = pb.environment(); env.put("VAR1", "myValue"); env.remove("OTHERVAR"); env.put("VAR2", env.get("VAR1") + "suffix"); pb.directory(new File("myDir")); Process p = pb.start();
В пакете SQL PreparedStatement можно рассматривать как экземпляр шаблона построителя:
PreparedStatement stmt = conn.prepareStatement(getSql()); stmt.setString(1, ...); stmt.setString(2, ...); ResultSet rs = stmt.executeQuery(); ... stmt.setString(2, ...); rs = stmt.executeQuery(); ...