在构造函数C#中使用类-它有味道吗?

在构造函数C#中使用类-它有味道吗?,c#,constructor,class-design,C#,Constructor,Class Design,下面的代码有味道吗?我正在重构一些代码,并发现了这种循环关系,其中foo需要一个类,该类需要一个foo自己实现的接口 在真正的代码中,foo是一个Silverlight用户控件,ifoo有一些方法来执行UI类型的操作,比如引发一个对话框(例如ShowMessage)。needsAnIfoo类是一种控制器,它可以在任何时候使用ifoo接口来处理UI。我有不同的“主题”UI,它们实现了iFoo,并且在它们的构造函数中有相同的锅炉板代码。needsAnIfoo具有各种属性,这些属性被数据绑定到UI(因

下面的代码有味道吗?我正在重构一些代码,并发现了这种循环关系,其中foo需要一个类,该类需要一个foo自己实现的接口

在真正的代码中,foo是一个Silverlight用户控件,ifoo有一些方法来执行UI类型的操作,比如引发一个对话框(例如
ShowMessage
)。
needsAnIfoo
类是一种控制器,它可以在任何时候使用ifoo接口来处理UI。我有不同的“主题”UI,它们实现了iFoo,并且在它们的构造函数中有相同的锅炉板代码。
needsAnIfoo
具有各种属性,这些属性被数据绑定到UI(因此它也是一种模型)

它编译和运行都很好,但我想知道是否有更好的方法

那么,它闻起来了吗

    interface ifoo
    {
        void bar();
    }

    class foo : ifoo
    {
        readonly needsAnIfoo _needsAnIfoo;
        internal foo()
        { 
            _needsAnIfoo = new needsAnIfoo(this);
        }

        #region ifoo Members
        public void bar()
        {
            throw new NotImplementedException();
        }
        #endregion
    }

    class needsAnIfoo
    {
        readonly ifoo _myfoo;
        public needsAnIfoo(ifoo foo)
        {
            _myfoo = foo;
        }
    }

    static void Main(string[] args)
    {
        foo foo = new foo();
    }
也许我应该在不将iFoo传递给构造函数的情况下重新创建
needsAnIfoo
,然后在
Initialize
方法中给它
iFoo
。但这看起来很奇怪:

    foo foo = new foo();
    needsAnIfoo needsAnIfoo = new needsAnIfoo(foo);
    foo.Initialise(needsAnIfoo);

我觉得不太对劲。闻起来很脆


您是否考虑过通过查看生成器或factory模式来创建相关对象并建立它们之间的关系?它可能会提供一种更安全的前进方式。

听起来是一个建立模式的好地方,我想说的是工厂方法

class Factory
{
public:
    virtual needsAnIfoo* Create(ProductId);
};

needsAnIfoo* Factory::Create(ProductId id)
{
    if (id == TYPE1) return new needsAnIfoo(ifooType1());
    if (id == TYPE2) return new needsAnIfoo(ifooType2());
    ...
    return 0;
}
那么你会这样使用它:

Factory f = new Factory();
theme1 = f.Create(TYPE1);
theme2 = f.Create(TYPE2);

我是你的朋友

我同意建筑商或工厂模式或类似模式会更好。所提供的代码不是很容易测试,而且,如前所述,有点脆弱,所以某种形式的依赖注入是不错的


要使用的模式将取决于foo和needsAnIFoo如何相互使用。你可能需要考虑观察者模式,如果NothAsIFOO是一个主题,Foo是一个观察者,而Bar()是一个更新方法。

< P>听起来这可能过于复杂,而且你正在使你的主题成为一个控制器,并且有一个控制器(通过两个类实现IFOO)

如果将主题控制器的概念分开,以便控制器有一个主题,您可能会得到更好的结果。然后,例如,当控制器执行某些操作时,例如弹出一个对话框,它会查看其主题以找出要使用的字体

像这样:

interface itheme {} // to describe properties of the theme
class theme : itheme {}// a bunch of different themes, this previously would have been the "foo" 
class theme2 :itheme{} //etc.

abstract class icontroller
{
    protected icontroller(itheme ptheme) {theme = ptheme;}

    protected itheme theme;

    //function declarations
    // ....

}
class control : icontroller {} // implements the icontrol functions.
//not sure if you need more than one control implementation... 
//  if not, i'd get rid of the icontrol interface.


//use it by passing a theme into the controller constructor:
icontroller myUIController = new control(new ClassicTheme()); 

我试图稍微理解一下这个问题,但是如果每个needsAnIfoo只绑定到一种类型的类,并且needsAnIfoo本身不做任何事情,那么您似乎可以使用扩展方法创建一个needsAnIfoo的静态类,而无需将其作为构造函数参数传递


这是一个有观察者的工厂-似乎做到了这一点,避免了在我的主题UI中更新“控制器”

   interface ifoo
    {
        void bar();
    }

    class foo : ifoo
    {
        public void bar() { Console.Write("do a foo type thing"); }
    }

    class foo2 : ifoo
    {
        public void bar() { Console.Write("do a foo2 type thing"); }
    }

    class needsAnIfoo
    {
        public event EventHandler SomethingIFooCanDealWith;
        System.Threading.Timer _timer;
        public needsAnIfoo()
        {
            _timer = new System.Threading.Timer(MakeFooDoSomething, null, 0, 1000);
        }

        void MakeFooDoSomething(Object state)
        {
            if (SomethingIFooCanDealWith != null) 
            {
                SomethingIFooCanDealWith(this,EventArgs.Empty);
            };
        }
    }

    class fooFactory
    {
        needsAnIfoo _needsAnIfoo = new needsAnIfoo();
        Dictionary<String, ifoo> _themedFoos = new Dictionary<string,ifoo>();
        ifoo _lastFoo = null;

        public void RegisterFoo(String themeName, ifoo foo)
        {
            _themedFoos.Add(themeName, foo);
        }

        public ifoo GetThemedFoo(String theme)
        {
            if (_lastFoo != null) { _needsAnIfoo.SomethingIFooCanDealWith -= (sender, e) => _lastFoo.bar(); };
            ifoo newFoo = _themedFoos[theme];
            _needsAnIfoo.SomethingIFooCanDealWith += (sender, e) => newFoo.bar();
            _lastFoo = newFoo;
            return newFoo;
        }
    }

    static void Main(string[] args)
    {
        fooFactory factory = new fooFactory();
        factory.RegisterFoo("CompanyA", new foo());
        factory.RegisterFoo("CompanyB", new foo2());

        ifoo foo = factory.GetThemedFoo("CompanyA");
        Console.Write("Press key to switch theme");
        Console.ReadKey();

        foo = factory.GetThemedFoo("CompanyB");
        Console.ReadKey();
    }
接口ifoo
{
空心钢筋();
}
foo类:ifoo
{
public void bar(){Console.Write(“做一个foo类型的事情”);}
}
第二类:ifoo
{
public void bar(){Console.Write(“执行foo2类型的操作”);}
}
类需要SANIFOO
{
公共事件事件处理程序somethingfoocandealwith;
System.Threading.Timer\u Timer;
公共需求Sanifoo()
{
_timer=newsystem.Threading.timer(MakeFooDoSomething,null,0,1000);
}
void MakeFooDoSomething(对象状态)
{
if(somethingingfoocandealwith!=null)
{
somethingFooCanDealWith(this,EventArgs.Empty);
};
}
}
食品级工厂
{
needsAnIfoo_needsAnIfoo=新的needsAnIfoo();
字典_-foos=新字典();
ifoo\u lastFoo=null;
公共无效寄存器foo(字符串themeName,ifoo foo)
{
_添加(主题名,foo);
}
公共ifoogetthemedfoo(字符串主题)
{
如果(_lastFoo!=null){u需要sanifoo.somethingiFoocandeallwith-=(发送方,e)=>\u lastFoo.bar();};
ifoo newFoo=_主题食品[主题];
_needsAnIfoo.SomethingIFooCanDealWith+=(发送方,e)=>newFoo.bar();
_lastFoo=newFoo;
返回newFoo;
}
}
静态void Main(字符串[]参数)
{
fooFactory=新fooFactory();
factory.RegisterFoo(“CompanyA”,newfoo());
RegisterFoo(“CompanyB”,newfoo2());
ifoo foo=factory.GetThemedFoo(“CompanyA”);
控制台。写入(“按键切换主题”);
Console.ReadKey();
foo=factory.GetThemedFoo(“CompanyB”);
Console.ReadKey();
}

不要重复某一点,但如果这是(新的?)设计,它肯定应该使用构造模式(工厂方法似乎最有意义)。是的,工厂方法将完成设计:)是的,谢谢,工厂似乎是一条路要走。我已经建立了一个原型工厂来制作我的“iFoos”-我将发布代码。谢谢你的例子!我马上就把我要去的地方贴出来了。终于超过你了!(我正在回顾一些旧帖子和合并账户,所以我只记得这篇帖子。)好的,我稍微重新安排了一些事情——我创建了一个工厂,并使用一个事件作为观察者模式的基础。我将在稍后发布我所做的。这不是一个真正的工厂——这更类似于Gamma等人提出的“Flyweight工厂”(第98页)。教科书工厂模式用于构建新对象;不提供对现有对象的引用。也就是说,模式是指导方针。我相信这段代码比原代码有了很大的改进,它是一种适用于,比如说,主题之间实时切换的模式(而不是在启动时选择,教科书工厂更适合这样);只是不是一个教科书工厂。一点也不坏;只是澄清工厂模式的意图!:D