Trying to evade the singleton / god / manager class. Not sure how I should support the functionality though

I have a class that grows steadily over time. It was called LayoutManager .

It started as a way to keep track of which dynamically generated controls were on my page. So, for example, I have this:

 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); } 

Thus, at the initial stages of the page life cycle, the controls will be recreated and they will add themselves to their checklist.

And after a while I found that I was passing a Page object between methods. This was for the sole purpose of gaining access to the controls found on the page. I thought to myself - well, I already have a layout manager, I just handle the static controls in the same way.

So my Page_Init method now looks like this mess:

 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(); } 

I look at it and say no, no, no. This is all wrong. However, there are controls on my page that are very dependent on each other, but do not have access to each other. This seems to make it so necessary.

I think a good example of this in practice would be to use UpdatePanels. So, for example, the DashboardUpdatePanel is passed to the LayoutManager. There are controls on the page, which, conditionally, should lead to updating the entire contents of the panel.

Now, in my opinion, I believe that I have two options:

  • Inside the object that wants to call UpdatePanel.Update (), I return through the parent objects, checking the type and identifier, until I find the corresponding UpdatePanel.
  • I am asking LayoutManager for UpdatePanel.

Clearly, the second scenario sounds cleaner ... but in many cases I use the same logic. This led to the creation of a manager class that looks like this:

 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; } } 

Am I a bad way? What steps are usually taken at this stage?

EDIT1: I decided to start the improvement path by finding controls that are the least integrated in the LayoutManager and find ways to break them down into separate objects. So, for example, instead of assigning the HistoricalReportsContainer and CustomReportsContainer objects to the LayoutManager (which is then used in the RegenerationManager.RegenerateReportMenu), I moved the code to the RadListBox "Download" event. There I check the identifier of the control, which loads and reacts accordingly. Strong first improvement and removed 2 controls and method from LayoutManager!

+6
source share
2 answers

Management inversion is the general approach that people use for such problems. Your dependencies should not be stored in the Jack-Bauer class of the style type, but rather entered, for example, through the constructor. Take a look at IoC containers like Castle Windsor, Unity, NInject, or whatever.

+1
source

I'm not sure how this will interact with future MVC plans, but have you considered refactoring pieces of LayoutManager into an abstract class that inherits from the page, and then your actual pages inherit from this abstract class?

0
source

Source: https://habr.com/ru/post/900320/


All Articles