我有一个Connections
需要异步初始化的类型.这种类型的实例被其他几种类型(例如Storage
)消耗,每种类型也需要异步初始化(静态,不是每个实例,并且这些初始化也依赖于Connections
).最后,我的逻辑类型(例如Logic
)使用这些存储实例.目前使用Simple Injector.
我尝试了几种不同的解决方案,但总有一种反模式存在.
我目前使用的解决方案有Temporal Coupling反模式:
public sealed class Connections
{
Task InitializeAsync();
}
public sealed class Storage : IStorage
{
public Storage(Connections connections);
public static Task InitializeAsync(Connections connections);
}
public sealed class Logic
{
public Logic(IStorage storage);
}
public static class GlobalConfig
{
public static async Task EnsureInitialized()
{
var connections = Container.GetInstance<Connections>();
await connections.InitializeAsync();
await Storage.InitializeAsync(connections);
}
}
Run Code Online (Sandbox Code Playgroud)
我已经将Temporal Coupling封装成一种方法,所以它并没有那么糟糕.但是,它仍然是一个反模式,而不是像我想的那样可维护.
常见的解决方案是抽象工厂模式.但是,在这种情况下,我们正在处理异步初始化.因此,我可以通过强制初始化同步运行来使用抽象工厂,但这会采用同步异步反模式.我真的不喜欢异步同步方法,因为我有几个存储空间,在我当前的代码中,它们都是同时初始化的; 由于这是一个云应用程序,将其更改为串行同步会增加启动时间,并且由于资源消耗,并行同步也不理想.
我也可以使用Abstract Factory和异步工厂方法.但是,这种方法存在一个主要问题.正如马克·西曼(Mark …
dependency-injection initialization abstract-factory async-await simple-injector
自从我在另一个stackoverflow问题上找到答案(现在精确的一个躲过我)之后,一直困扰着我的事情,用户说的话" 如果你正在调用服务定位器,那你做错了. "
这是一个声誉很高的人(我认为是十万人)所以我倾向于认为这个人可能知道他们在谈论什么.自从我第一次开始学习它以及它与单元测试有什么关系以及什么不是,我一直在为我的项目使用DI.这是我现在很满意的事情,我想我知道自己在做什么.
但是,有很多地方我一直在使用服务定位器来解决项目中的依赖项.一旦主要示例来自我的ModelBinder实现.
典型模型装订器的示例.
public class FileModelBinder : IModelBinder {
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
ValueProviderResult value = bindingContext.ValueProvider.GetValue("id");
IDataContext db = Services.Current.GetService<IDataContext>();
return db.Files.SingleOrDefault(i => i.Id == id.AttemptedValue);
}
}
Run Code Online (Sandbox Code Playgroud)
不是一个真正的实现 - 只是一个简单的例子
由于ModelBinder实现在首次请求Binder时需要新实例,因此无法在构造函数上使用依赖注入来实现此特定实现.
在我的很多课程中都是这样的.另一个例子是Cache Expiration进程,它在我的网站中缓存对象到期时运行一个方法.我运行了一堆数据库调用,什么不是.我也使用服务定位器来获得所需的依赖项.
我最近遇到的另一个问题(我在这里发布了一个问题)是我的所有控制器都需要一个IDataContext实例,我使用了DI - 但是一个动作方法需要一个不同的IDataContext实例.幸运的是,Ninject通过命名的依赖来救援.然而,这感觉像一个kludge而不是一个真正的解决方案.
我认为我至少理解了分离关注的概念,但是我理解依赖注入和服务定位器模式似乎存在根本性的错误 - 我不知道那是什么.
我目前理解它的方式 - 这也可能是错误的 - 至少在MVC中,ControllerFactory为Controller查找构造函数并调用服务定位器本身以获取所需的依赖关系,然后将它们传入.但是,我可以理解,不是所有的类和没有工厂创建它们.所以在我看来,一些服务定位器模式是可以接受的......但......
我想就是这样 - 我无法想到任何其他问题来帮助我理解,但非常感谢任何额外的信息.
我知道DI可能不是解决所有问题的方法,但我可能会在实现它的过程中过分关注,但是,它似乎按照我期望的方式进行单元测试,而不是.
我不是在寻找代码来修复我的示例实现 - 我正在寻找学习,寻找解释以修复我的错误理解.
我希望stackoverflow.com能够保存草稿问题.我也希望无论谁回答这个问题都能获得适当的声誉来回答这个问题,因为我觉得我要求很多.提前致谢.
dependency-injection ninject service-locator abstract-factory asp.net-mvc-3
我刚刚学习了Bridge
Pattern及其意图:将抽象与其实现分离,以便两者可以独立变化.
但为什么不能AbstractFactory
做同样的事情呢?
我知道一个AbstractFactory
可以创建一个特定的桥梁,但我的问题涉及使用AbstractFactory
而不是Bridge
解耦抽象和实现.
你能解释一下AbstractFactory
和Bridge
Pattern 之间的真正区别吗?
我已经看到了使用静态方法的Factory实现.像这样的东西:
public class MyFactory {
public static Product1 createProduct1() {}
public static Product2 createProduct2() {}
}
p1 = MyFactory.createProduct1();
p2 = MyFactory.createProduct2();
Run Code Online (Sandbox Code Playgroud)
我不确定我是否可以将其称为抽象工厂,但这不是问题.我对抽象工厂的理解是,它为我们提供了轻松更改产品系列的灵活性.
Factory factory = new MyFactory(); // might be a global or Singleton
p1 = factory.createProduct1();
p2 = factory.createProduct2();
Run Code Online (Sandbox Code Playgroud)
如果我想改变MyFactory
,YourFactory
那么只需要改变一行.我也可以在运行时更改它.但它们是否可以作为静态方法实现?我需要将所有调用更改为静态工厂.如果我们想在运行时决定,还需要在每个地方使用if-else检查.
p1 = YourFactory.createProduct1();
p2 = YourFactory.createProduct2();
Run Code Online (Sandbox Code Playgroud)
那么使用静态方法实现工厂的好处是什么?我们不是失去了主要的灵活性吗?我错过了什么?
请注意,不承担任何特定语言.任何帮助表示赞赏.
static design-patterns factory factory-pattern abstract-factory
问题
我有两个我要测试的Android类:
CommentContentProvider
,它扩展ContentProvider
并由SQLiteDatabase支持.CommentActivity
,通过一个间接扩展Activity
和访问.CommentContentProvider
ContentResolver
我目前有两个测试类:
CommentContentProviderTest
,扩展ProviderTestCase2<CommentContentProvider>
和使用MockContentResolver
.这很好用.CommentActivityTest
,延伸ActivityInstrumentationTestCase2<CommentActivity>
.除了CommentActivity
访问的部分外,这种方法很好CommentContentProvider
.问题是,当CommentActivity
访问时CommentContentProvider
,它通过标准这样做ContentResolver
:
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver().query(...);
Run Code Online (Sandbox Code Playgroud)
因此,当CommentActivityTest
运行时,它会启动CommentActivity
,访问(读取和写入)生产数据库,如上面两行所示.
我的问题是如何在生产中CommentActivity
使用标准ContentResolver
,但MockContentResolver
在测试期间.
相关问题
Activity
.可能的解决方案
如果我可以通过启动的Intent注入ContentResolver
(可能是a MockContentResolver
或RenamingDelegatingContext
),那将是很好的,但我不能这样做,因为s不是.CommentActivity
Context
Parcelable …
android dependency-injection abstract-factory android-contentresolver android-testing
我试图尽可能多地使用依赖注入,但是当涉及短期依赖项等问题时我遇到了麻烦.
例如,假设我有一个博客管理器对象,希望生成它在数据库中找到的博客列表.这样做的选项(据我所知)是:
但是,#1很糟糕,因为它会产生强耦合.#2仍然看起来很糟糕,因为这意味着必须事先注入对象工厂 - 暴露它可以创建的所有其他对象.
3号似乎没问题,但如果我使用#3,我是否将"new"关键字放在blogEntryFactory本身中,或者,我是否将加载器注入blogEntryFactory并使用加载器?
如果我有许多不同的工厂,比如blogEntryFactory(例如我可以拥有userFactory和commentFactory),那么在所有这些不同的工厂中放置"new"关键字就会产生依赖性问题.
我希望这是有道理的...
注意
我已经得到了一些关于这个特定博客示例如何不必要的答案,但事实上,你应该使用抽象工厂模式的情况,这就是我得到的观点.你是在这种情况下使用"新"还是做其他事情?
给出一个抽象的工厂实现:
public class FooFactory : IFooFactory {
public IFoo Create(object param1, object param2) {
return new Foo(param1, param2);
}
}
Run Code Online (Sandbox Code Playgroud)
为这堂课写什么单元测试?如何验证param1和param2是否已转发到Foo的创建?我是否必须制作Foo的这些公共属性?这不会破坏封装吗?或者我应该将其留给集成测试?
我正在学习设计模式,本书的第一个例子是关于抽象工厂.我在VS中建立了这个练习并且看起来都很好,但是有一个我想知道的问题.
在本书中,工厂类是这样实现的:
public abstract class AbstractVehicleFactory
{
public abstract IBody CreateBody();
public abstract IChassis CreateChassis();
public abstract IGlassware CreateGlassware();
}
Run Code Online (Sandbox Code Playgroud)
完成练习后,我注意到上面的类可以用以下代码替换:
public interface IAbstractVehicleFactory
{
IBody CreateBody();
IChassis CreateChassis();
IGlassware CreateGlassware();
}
Run Code Online (Sandbox Code Playgroud)
当然这两个例子的功能完全相同,但我想知道使用抽象类而不是接口的原因是什么?
来自GOF书:
类模式处理类及其子类之间的关系.这些关系是通过继承建立的,因此它们在编译时是静态修复的.对象模式 处理对象关系,可以在运行时更改它们并且更加动态.几乎所有模式都在某种程度上使用继承.所以标记为"类模式"的唯一模式是那些关注类关系的模式.
为什么工厂方法是一个类模式,而抽象工厂是一个对象模式,因为它们似乎是非常相似的模式?
谢谢.
我正在使用一个抽象工厂来返回具体子类的实例.我想在给定具体类名的String的情况下在运行时实例化子类.我还需要将参数传递给构造函数.类结构如下:
abstract class Parent {
private static HashMap<String, Child> instances = new HashMap<String,Child>()
private Object constructorParameter;
public static Child factory(String childName, Object constructorParam){
if(instances.keyExists(childName)){
return instances.get(childName);
}
//Some code here to instantiate the Child using constructorParam,
//then save Child into the HashMap, and then return the Child.
//Currently, I am doing:
Child instance = (Child) Class.forName(childClass).getConstructor().newInstance(new Object[] {constructorParam});
instances.put(childName, instance);
return instance;
}
//Constructor is protected so unrelated classes can't instantiate
protected Parent(Object param){
constructorParameter = param;
}
}//end Parent …
Run Code Online (Sandbox Code Playgroud)