Advertisement
Guest User

Untitled

a guest
Feb 21st, 2019
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.93 KB | None | 0 0
  1. Code: RocketLanding
  2. Date: 2019.01.15
  3. Reviewer: Tiziana Brinzas
  4.  
  5. Part I
  6. Algorithms
  7.  
  8. 1. IDataSpecificInfo has a very odd interface. It should not be its concern to manage a number of devices, but simply to return one specific info.
  9. Please change its interface to:
  10. LandingDeviceSpecificInformation GetDeviceSpecificInformation();
  11.  
  12. 2. DataSpecificProvider should be static (only has one static method)
  13.  
  14. 3. LandingDevice should not keep the Planet and BurningRate as members, these are actually characteristics of commands. Instead, the BreakCommand and FreeFall methods should take a Planet as parameter. Get rid of all the small Adjust... members, they do not bring benefit, but force you to remember the context (hence the above Planet and BurningRate at the level of LandingDevice)
  15.  
  16. 4. Properties are not meant to be used exclusively with dumb get/setters. Turn GetTotalMass() and ItLandedSafely() (should be called HasLandedSafely) into get-only properties. This will come in handy later on with binding to the view model.
  17.  
  18. 5. ItLandedSafely only checks the speed, but does not check if it actually landed...
  19.  
  20. 6. The Land methods started to multiply... you should only have: LandCommand(Planet planet, Command command). IMHO the logic of sequencing commands belongs to the ControlTower, but if you must have LandCommand(Planet planet, IEnumerable<Command> commands) here, then make sure the single command version calls the enumeration version with a single-element array:
  21.  
  22. public override void Land(Planet planet, Command command)
  23. {
  24. Land(planet, new[] { command });
  25. }
  26.  
  27. 7. You have introduced a FreeFall method in LandingDevice, but in ControlTower you create a special command for that. Either have a
  28. public void FreeFall(Planet planet, double seconds) and use that in ControlTower as well, or get rid of it all together and just use BreakCommand.
  29.  
  30. 8. Did you read about linq? If not, please go back to that. ControlTower.InitializeRockets and ControlTower.FindRocketByRocketId should be rewritten using linq. And, btw, get rid of the LandDeviceStopWatches class - you do not need it.
  31.  
  32. 9. Why is the control tower assigning Ids to landing devices? Shouldn't this be done by the data source? If you need this information, then provide it (even if randomly generated) from the data source, and make sure you validate it; otherwise identify devices by reference, not by their Id.
  33.  
  34.  
  35.  
  36. Part II
  37. LandingDemo
  38.  
  39. 1. RelayCommand:
  40.  
  41. 1.0 See https://onewindowsdev.com/2016/06/16/the-command-pattern-and-mvvm/ article for an example of using commands and their relation w. MVVM
  42.  
  43. 1.1 Your implementation of ICommand is crippled: you cannot pass a CanExecute method, and you cannot pass arguments to either Execute or CanExecute.
  44.  
  45. 1.2 The CanExecuteChanged event handler is supposed to notify the UI when CanExecute changes its mind, something that your implementation currently
  46. does not allow. But commands are intended to be directly bound to, e.g. buttons; when you do that and the command CanExecuteChanged event is raised, the button's enabled state changes accordingly. Provided, of course, that you stick to the interface (and its intentions). This means you should replace the mere declaration of the event with:
  47.  
  48. public event EventHandler CanExecuteChanged
  49. {
  50. add { CommandManager.RequerySuggested += value; }
  51. remove { CommandManager.RequerySuggested -= value; }
  52. }
  53.  
  54. and actually implement and use the CanExecute part.
  55.  
  56. 1.3 Usually a view model only needs to instantiate a command once in its lifetime. Instead of creating a new command every time your getter is called,
  57. create it once and cache it in a private variable (see below example from our project):
  58.  
  59. private ICommand _nextPageCommand;
  60. public ICommand NextPageCommand
  61. {
  62. get
  63. {
  64. return this._nextPageCommand ?? (this._nextPageCommand = new DelegateCommand(
  65. () => this.CurrentFrame++,
  66. () => this.IsImageLoaded && this.CurrentFrame < this.FrameCount - 1)
  67. .ObservesProperty(() => this.IsImageLoaded)
  68. .ObservesProperty(() => this.CurrentFrame));
  69. }
  70. }
  71.  
  72.  
  73. 2. ViewModelBase
  74.  
  75. 2.0 See https://github.com/PrismLibrary/Prism/blob/master/Source/Prism/Mvvm/BindableBase.cs for a nice implementation of this. Please study it.
  76.  
  77. 2.1 It would be better to include a more complete implementation of the basic view model, one that provides get/set implementations for properties.
  78. It is important that you understand how notification changes are used by the binding mechanism, and that each notification is the potential source of
  79. a cascade of notifications that eventually will refresh your UI. Consequently, all setters should check if the value actually changed before issuing a
  80. property changed notification. And this is better done in the base class, to avoid duplicating this code all over again.
  81.  
  82. 2.2 You are better off using the [CallerMemberName] attribute instead of relying on the caller to pass the correct property name to you.
  83.  
  84. 2.3 Wherever you call OnPropertyChanged("<some_property>"), replace it with OnPropertyChanged(nameof(<some_property>)).
  85. If you decide one day to rename the property, the latter version would automatically pick up the change.
  86.  
  87.  
  88. 3. ViewModels
  89.  
  90. 3.0 I have the impression you are unclear about the roles each plays. Please see https://www.wintellect.com/model-view-viewmodel-mvvm-explained/
  91.  
  92. 3.1 There seems to be no relation between your models and the corresponding view models. Normally a view model is built on top of (a) model(s), i.e.
  93. the constructor should have some model-related argument.
  94.  
  95. 3.2 I do not understand why are there a LandingDeviceViewModel and a RocketViewModel, and what is the intended relationship between them. But the RocketViewModel seems outright wrong: accessing protected/private properties defeats the purpose of encapsulation. While this is arguably acceptable in unit-tests, it is definitely not a good idea in productive code. Besides, you're even exposing properties that should not be there in the first place (see Part I, point 3)
  96.  
  97. 3.3 The pattern you see illustrated via INotifyPropertyChanged is not limited, in its usage, to view models. It is actually a general use observer,
  98. and you can make use of it at any level, for instance in the communication between the view model and model. If your model notifies of changes in its properties, and the view model listens to its properties and updates its own, you can get rid of the limited and error-prone refresh methods, which prevents you from getting "live" updates, and instead delivers fresh data only when explicitly called.
  99.  
  100. Rewrite the code to propagate changes via binding instead of explicitly calling some method, so that we get the update when the property actually changes, not when we ask of it. Both ControlTower.RefreshStatus and ControlTower.CalculateAllSafeStates methods should go away. In fact, what business does the ControlTower have calculating things that pertain exclusively to the LandingDevice??
  101.  
  102. 3.4 Linq again: all calls like x.Count() > 0 should be replaced with x.Any()
  103.  
  104. 3.5 Type specifiers in calls like landingDevices.ElementAt<LandingDeviceViewModel>(i) is redundant. Get rid of it.
  105.  
  106. 3.6 Parentheses in constructor followed by property initializers like var rockeVM = new LandingDeviceViewModel() {...} are redundant. Get rid of it.
  107.  
  108. 3.7 We discussed before about naming standards: property names should begin with capital letter, arguments should not. You are mixing it everywhere, please correct.
  109.  
  110. 3.8 We discussed before about exceptions, yet you have again empty catch clauses, which will hide errors. Please correct.
  111.  
  112. 3.9 Why is there a static instance of a ControlTower? You're not using it anywhere...
  113.  
  114. 3.10 InitializeTower and Destroy tower have no place existing, at least not in the ControlTowerViewModel. Initializing the data source is typically done at application start, based on some external configuration. And that should cover the ControlTower instance. The view model should be able to construct itself from that.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement