试图避开单例/神/经理类.但我不确定我应该如何维持功能
本文关键字:不确定 我应该 功能 何维持 单例 | 更新日期: 2023-09-27 18:12:38
随着时间的推移,我有一个班级一直在稳步增长。它叫做LayoutManager
。
它开始是我跟踪页面上哪些动态创建的控件的一种方式。例如,我有这个:
public CormantRadDockZone()
{
ID = String.Format("RadDockZone_{0}", Guid.NewGuid().ToString().Replace('-', 'a'));
MinHeight = Unit.Percentage(100);
BorderWidth = 0;
HighlightedCssClass = "zoneDropOk";
CssClass = "rightRoundedCorners";
LayoutManager.Instance.RegisteredDockZones.Add(this);
}
这样,在页面生命周期的开始阶段,控件将被重新创建,并且它们将自己添加到各自的控件列表中。
过了一会儿,我发现自己在方法之间传递了'Page'对象。这样做的唯一目的是能够访问Page上的控件。我对自己说——好吧,我已经有了布局管理器,我就用同样的方式来处理静态控件。
因此,我的Page_Init方法现在看起来像这样:protected void Page_Init(object sender, EventArgs e)
{
SessionRepository.Instance.EnsureAuthorized();
LayoutManager.Instance.RegisteredPanes.Clear();
LayoutManager.Instance.RegisteredDocks.Clear();
LayoutManager.Instance.RegisteredDockZones.Clear();
LayoutManager.Instance.RegisteredSplitters.Clear();
LayoutManager.Instance.RegisteredSplitBars.Clear();
LayoutManager.Instance.RegisteredPageViews.Clear();
LayoutManager.Instance.CheckBox1 = CheckBox1;
LayoutManager.Instance.CheckBox4 = CheckBox4;
LayoutManager.Instance.StartEditButton = StartEditButton;
LayoutManager.Instance.FinishEditButton = FinishEditButton;
LayoutManager.Instance.RadNumericTextBox1 = RadNumericTextBox1;
LayoutManager.Instance.RadNumericTextBox2 = RadNumericTextBox2;
LayoutManager.Instance.LeftPane = LeftPane;
LayoutManager.Instance.DashboardUpdatePanel = DashboardUpdatePanel;
LayoutManager.Instance.CustomReportsContainer = CustomReportsContainer;
LayoutManager.Instance.HistoricalReportsContainer = HistoricalReportsContainer;
RegenerationManager.Instance.RegenerateReportMenu();
LayoutManager.Instance.MultiPage = DashboardMultiPage;
LayoutManager.Instance.MultiPageUpdatePanel = MultiPageUpdatePanel;
LayoutManager.Instance.TabStrip = DashboardTabStrip;
RegenerationManager.Instance.RegenerateTabs(DashboardTabStrip);
RegenerationManager.Instance.RegeneratePageViews();
LayoutManager.Instance.Timer = RefreshAndCycleTimer;
LayoutManager.Instance.Timer.TimerEvent += DashboardTabStrip.DoTimerCycleTick;
RegenerationManager.Instance.RegeneratePageState();
}
我看着它说不,不,不。这都是错的。然而,我的页面上有一些控件彼此非常依赖,但彼此不能访问。这就是为什么这么做是必要的。
我认为这在实践中的一个很好的例子是使用UpdatePanels。因此,例如,DashboardUpdatePanel
被给予LayoutManager。页面上有一些控件,它们有条件地导致仪表板的整个内容更新。
现在,在我看来,我有两个选择:
- 在想要调用UpdatePanel. update()的对象中,我通过父对象递归向上,检查类型和ID,直到找到合适的UpdatePanel。
- 我问LayoutManager的UpdatePanel。
显然,在这种情况下,第二个听起来更干净……但我发现自己在很多情况下都使用同样的逻辑。这就产生了一个管理器类,如下所示:
public class LayoutManager
{
private static readonly ILog _logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly LayoutManager _instance = new LayoutManager();
private LayoutManager() { }
public static LayoutManager Instance
{
get { return _instance; }
}
private IList<CormantRadDock> _registeredDocks;
private IList<CormantRadDockZone> _registeredDockZones;
private IList<CormantRadPane> _registeredPanes;
private IList<CormantRadSplitter> _registeredSplitters;
private IList<CormantRadSplitBar> _registeredSplitBars;
private Dictionary<string, StyledUpdatePanel> _registeredUpdatePanels;
private IList<CormantRadPageView> _registeredPageViews;
public RadMultiPage MultiPage { get; set; }
public CormantTimer Timer { get; set; }
public CormantRadListBox HistoricalReportsContainer { get; set; }
public CormantRadListBox CustomReportsContainer { get; set; }
public StyledUpdatePanel MultiPageUpdatePanel { get; set; }
public CormantRadTabStrip TabStrip { get; set; }
public RadPane LeftPane { get; set; }
public StyledUpdatePanel DashboardUpdatePanel { get; set; }
public RadButton ToggleEditButton { get; set; }
public CheckBox CheckBox1 { get; set; }
public CheckBox CheckBox4 { get; set; }
public RadNumericTextBox RadNumericTextBox1 { get; set; }
public RadNumericTextBox RadNumericTextBox2 { get; set; }
public RadButton StartEditButton { get; set; }
public RadButton FinishEditButton { get; set; }
public IList<CormantRadDock> RegisteredDocks
{
get
{
if (Equals(_registeredDocks, null))
{
_registeredDocks = new List<CormantRadDock>();
}
return _registeredDocks;
}
}
public IList<CormantRadDockZone> RegisteredDockZones
{
get
{
if (Equals(_registeredDockZones, null))
{
_registeredDockZones = new List<CormantRadDockZone>();
}
return _registeredDockZones;
}
}
public IList<CormantRadPane> RegisteredPanes
{
get
{
if (Equals(_registeredPanes, null))
{
_registeredPanes = new List<CormantRadPane>();
}
return _registeredPanes;
}
}
public IList<CormantRadSplitter> RegisteredSplitters
{
get
{
if (Equals(_registeredSplitters, null))
{
_registeredSplitters = new List<CormantRadSplitter>();
}
return _registeredSplitters;
}
}
public IList<CormantRadSplitBar> RegisteredSplitBars
{
get
{
if (Equals(_registeredSplitBars, null))
{
_registeredSplitBars = new List<CormantRadSplitBar>();
}
return _registeredSplitBars;
}
}
public Dictionary<string, StyledUpdatePanel> RegisteredUpdatePanels
{
get
{
if( Equals( _registeredUpdatePanels, null))
{
_registeredUpdatePanels = new Dictionary<string, StyledUpdatePanel>();
}
return _registeredUpdatePanels;
}
}
public IList<CormantRadPageView> RegisteredPageViews
{
get
{
if (Equals(_registeredPageViews, null))
{
_registeredPageViews = new List<CormantRadPageView>();
}
return _registeredPageViews;
}
}
public StyledUpdatePanel GetBaseUpdatePanel()
{
string key = MultiPage.PageViews.Cast<CormantRadPageView>().Where(pageView => pageView.Selected).First().ID;
return RegisteredUpdatePanels[key];
}
public CormantRadDockZone GetDockZoneByID(string dockZoneID)
{
CormantRadDockZone dockZone = RegisteredDockZones.Where(registeredZone => dockZoneID.Contains(registeredZone.ID)).FirstOrDefault();
if (Equals(dockZone, null))
{
_logger.ErrorFormat("Did not find dockZone: {0}", dockZoneID);
}
else
{
_logger.DebugFormat("Found dockZone: {0}", dockZoneID);
}
return dockZone;
}
public CormantRadPane GetPaneByID(string paneID)
{
CormantRadPane pane = RegisteredPanes.Where(registeredZone => paneID.Contains(registeredZone.ID)).FirstOrDefault();
if (Equals(pane, null))
{
_logger.ErrorFormat("Did not find pane: {0}", paneID);
}
else
{
_logger.DebugFormat("Found pane: {0}", paneID);
}
return pane;
}
public CormantRadDock GetDockByID(string dockID)
{
CormantRadDock dock = RegisteredDocks.Where(registeredZone => dockID.Contains(registeredZone.ID)).FirstOrDefault();
if (Equals(dock, null))
{
_logger.ErrorFormat("Did not find dock: {0}", dockID);
}
else
{
_logger.DebugFormat("Found dock: {0}", dockID);
}
return dock;
}
}
我走错路了吗?在这一点上通常采取什么步骤?
EDIT1:我决定通过找到与LayoutManager集成最少的控件并找到将它们分解为单独对象的方法来开始改进路径。因此,例如,不是将HistoricalReportsContainer和CustomReportsContainer对象分配给LayoutManager(然后在RegenerationManager.RegenerateReportMenu中使用),而是将代码移动到RadListBox"Load"事件。在那里,我检查正在加载的控件的ID并做出相应的反应。一个强大的第一个改进,并从LayoutManager删除了2个控件和一个方法!
控制反转是人们用于解决此类问题的一般方法。您的依赖项不应该存储在一个类似jack - bauer风格的类中,而应该被注入,例如通过构造函数。看看IoC容器,如Castle Windsor, Unity, NInject或其他。
我不确定这将如何与MVC的未来计划交互,但是您是否考虑过将LayoutManager的块重构为继承自Page的抽象类,然后让您的实际页面继承自该抽象类?