Let's say I have an object that represents an electrical circuit.
public class Circuit
{
private int? resistance;
private int? current;
private int? voltage;
}
Given that current = voltage/resistance I can calculate the unknown property if I know the other two.
My first thought was that naturally the relationship between the properties should be built into the object. So that when setting any of the properties an unknown can be autofilled if the other two are known. This would work fine until a situation arises where all properties are set and one needs to be modified resulting in confusion over which of the other two properties should be modified to enforce the relationship. The other properties I suppose would need to be set to null at this point.
Is having setters with side effects like this viewed as acceptable practice? Are there other ways of enforcing such a relationship?
Further info
This is a simplified representation. The resistance could also be determined by inputting wire length and diameter and a resistance constant, I could also have wattage and phase. I am working in a databound scenario and have to persist the state of the object. As the number of properties increases and their relationship to one another gets more complex my setters get a little out of control.
You shouldn't set the current property in the resistance or voltage setter. Instead simply calculate the value in the current getter.
public class Conductor
{
private int? resistance;
private int? current() { return voltage/resistance; }
private int? voltage;
}
Your actual problem is that your assumption is wrong: A conductor in a circuit is not defined by its resistance, current and voltage, but only any two of them: The third one (regardless which) is implied by the values of the others. Therefore, you only need two attributes to describe a fully determined state of your conductor. Lets take resistance and voltage for simplicity. Then, to enforce the relationship between current and voltage, you could write:
public class Conductor
{
private float resistance;
private float voltage;
public void setVoltage( float voltage )
{
this.voltage = voltage;
}
public float getVoltage()
{
return voltage;
}
public float getCurrent()
{
return getVoltage() / getResistance();
}
public void setCurrent( float current )
{
this.voltage = current * getResistance();
}
public void setResistance( float resistance )
{
this.resistance = resistance;
}
public void setResistance( float current, float voltage )
{
setResistance( voltage / current );
}
public float getResistance()
{
return resistance;
}
}
For any further setters, such as setting the conductor's resistance based on wire length, diameter and a resistance constant, you won't require any new attributes (!) but only the setters themselves:
public void setResistance( float constant, float diameter, float length )
{
this.resistance = constant * length / ( 2 * Math.PI * diameter * diameter );
}
Same is true for further getters:
public float getResistanceConstant( float diameter, float length )
{
return ( getResistance() * ( 2 * Math.PI * diameter * diamter ) ) / length;
}
If you nevertheless need to store diameter as an attribute, you should derive a class Wire from Conductor, since not every conductor's resistance is defined by it's length, diameter and resistance constant, but only those of wires. But remember: Again, you won't need to store all the three values as arguments, but only two of them - the third one's value is already implicitly defined, since you got the resistance as an attribute.
Related
Here's a bare minimum pseodo-code of what I use:
class A{
//other variables
B b;
void delayedPartnerInit(B b){
this.b=b;
}
}
class B{
//some other variables
A a;
void delayedPartnerInit(A a){
this.a=a;
}
}
I could make it into a single class but certain members(not shown here) of A are needed to exist before data about B. In other words, objects of A and B are instanced at different times but need reference of each other's variables once both set of variables are available.
The question is there a better way to do this? Am I missing some basic concept of programming?
Though I am currently working on C#, I have had this thought many times before when working with other languages too.
Update: I am using this in Unity game engine where B is Unity C# script. Since Unity doesn't allow us create scripts without adding it to something I need 2 classes. I get certain data(A's data) earliar which needs processing.
Didn't mention this earlier because I asked it as a generic question.
Note before closing as duplicate: I checked similar questions but found only specific questions that caused issues to authors who tried to do what I am doing. My question is whether it is a bad practice.
Tightly coupled classes are generally bad practice:
Changes in one class lead to changes in another.
You cannot test one of classes without creating (or mocking) another one. Which in your case creates circular dependency.
Both classes depend on each other's implementations, not abstractions.
Harder for other persons (or yourself half a year later) to understand and reason about first class logic without inspecting second class as well.
Since Unity doesn't allow us create scripts without adding it to something I need 2 classes. I get certain data(A's data) earliar which needs processing
MVC pattern for Unity provides useful trick for decoupling monobehaviours:
interface ISomeObjectView {
event Action OnUpdate;
event Action Destroyed;
event Action TriggerEntered;
void SetTransform(Vector3 position, Quaternion rotation);
void AddForce(Vector3 force);
// Other methods or events you need to expose:
// MouseOver, OnFixedUpdate, Move() or SetScale(), ...
}
MonoBehaviour itself does not contain any logic, it simply invokes events and uses incoming values:
public void SetTransform(Vector3 position, Quaternion rotation)
{
// Params validation
transform.rotation = rotation;
transform.position = position;
}
private void Update()
=> OnUpdate?.Invoke();
MonoBehaviour logic must be moved to your data class or new controller class. Now your data class simply links itself to provided interface events and methods without circular dependencies. Monobehaviour does not require any references to other classes, it simply provides methods to manipulate itself and events to catch input.
This trick helps in several ways:
MonoBehaviour doesn't depend on anything and doesn't require any references to other classes.
Your data/logic classes doesn't require ant special knowledge about monobehaviours, only provided interface.
You can have several implementations for interface, switching different views depending on situation.
Easy to test, easy to mock.
You can move all the "Unity stuff" inside MonoBehaviour and write all related classes on pure C#. If you want to.
Please note that using event Action is not conventional way to deal with events! I think it's very convenient, but I'd suggest to use conventional EventHandler (UnityEvents is another option that might suit your needs).
Update: an example of simple MVC.
Consider the following Player controller:
[Serializable]
public class PlayerInfo {
// Values configurable via inspector
[SerializeField] private float speed = 1.5f;
[SerializeField] private float jumpHeight = 5;
[SerializeField] private float damage = 15;
[SerializeField] private Player playerPrefab;
public float Speed => speed;
public float JumpHeight => jumpHeight ;
public float Damage => damage;
private Player playerInstance;
public void InitializePlayer() {
playerInstance = Instantiate(playerPrefab);
playerInstance.Info = this;
}
public void TeleportTo(Vector3 newPosition) {
playerInstance.transform.position = newPosition;
}
}
public class Player : MonoBehaviour {
public PlayerInfo Info { get; set; }
private Rigidbody rb;
private void Awake() {
rb = GetComponent<Rigidbody>();
}
private void Update() {
if (Input.GetButtonDown("Jump")
rb.AddForce(Vector3.up * info.JumpHeight);
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
rb.AddForce(movement * info.Speed);
}
private void OnTriggerEnter(Collider other) {
var enemy = other.GetComponent<Enemy>();
if (enemy != null)
enemy.TakeHit(info.Damage);
}
}
There you go. PlayerInfo is created before Player. PlayerInfo references Player and Player references PlayerInfo. Player is used to move gameobject and attack enemies, PlayerInfo contains required info. What can we do here?
First, Rewrite MonoBehaviour without any logic:
public class PlayerView : MonoBehaviour {
private Rigidbody rb;
// Events for future subscription.
public event Action OnUpdate;
public event TriggerEntered<Collider>;
// Simple initialization of required components.
private void Awake() {
rb = GetComponent<Rigidbody>();
}
// Unity methods doing nothing but invoking events.
private void Update() {
OnUpdate?.Invoke();
}
private void OnTriggerEnter(Collider other) {
TriggerEntered?.Invoke(other);
}
// We still need a method to move our player, right?
public void Move(Vector3 direction) {
rb.AddForce(direction);
}
public void SetPosition(Vector3 position) {
transform.position = position;
}
}
Now you need class containing data about player:
[Serializable]
public class PlayerModel {
[SerializeField] private float speed = 1.5f;
[SerializeField] private float jumpHeight = 5;
[SerializeField] private float damage = 15;
public float Speed => speed;
public float JumpHeight => jumpHeight ;
public float Damage => damage;
}
Now we need a way to tie those two together:
public class PlayerController {
private readonly PlayerModel model;
private readonly PlayerView view;
public PlayerController(PlayerModel model, PlayerView view) {
// Validate values here.
this.model = model;
this.view = view;
// Linking logic to events.
view.OnUpdate += Move;
view.TriggerEntered += Attack;
}
// Actual logic moved here.
private void Move() {
Vector3 movement = Vector3.zero;
if (Input.GetButtonDown("Jump")
movement += Vector3.up * model.JumpHeight;
movement += new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * model.Speed;
view.Move(movement);
}
private void Attack(Collider other) {
var enemy = other.GetComponent<Enemy>();
if (enemy != null)
enemy.TakeHit(model.Damage);
}
// Method from PlayerInfo to set player position without actual movements.
public void MoveTo(Vector3 position) {
view.SetPosition(position);
}
}
Now you have 3 classes instead of 2, but model and view classes are very simple and do not require any dependencies. All the work is done by Controller class, which receives other two pieces and ties them together.
It becomes even better when interfaces are introduced in addition to classes: IPlayerModel, IPlayerView, IPlayerController.
You might think that it would be easier to create single class instead of three linked classes, but in the long run you will thank yourself for using this pattern: view and model are extremely simple, easy to read, easy to check for errors, easy to expand with new functionality. Single class, on the other hand, will quickly grow to hundreds of lines and become a nightmare to test and expand.
I strongly recommend this article with more complicated examples of MVC.
com.fasterxml.jackson.datatype.joda.ser.DateTimeSerializer#DateTimeSerializer(JacksonJodaDateFormat format, int shapeOverride)
I can't figure out the meaning of shapeOverride. Could not find proper information on the internet about it. So what does it mean, what is it for?
This is a hint to Jackson to tell it what the fields "shape" is. Shape is basically data type. I don't know if you have ever serialized a Joda object and got an array before, but this is basically shape.
Is it an Array, String, or Timestamp?
The override is any non-0 value. So if you provide 0 you will get the default, and the default is ARRAY.
So pass the following based on how you want to serialize your data:
No Override = 0
STRING = 1
TIMESTAMP = 2
ARRAY = 3
You can see their explination in com.fasterxml.jackson.datatype.joda.ser.JodaDateSerializerBase
public abstract class JodaDateSerializerBase<T> extends JodaSerializerBase<T>
// need contextualization to read per-property annotations
implements ContextualSerializer
{
private static final long serialVersionUID = 1L;
// // Since 2.9
protected final static int FORMAT_STRING = 1;
protected final static int FORMAT_TIMESTAMP = 2;
protected final static int FORMAT_ARRAY = 3;
protected final JacksonJodaDateFormat _format;
protected final SerializationFeature _featureForNumeric;
/**
* Shape to use for generic "use numeric" feature (instead of more specific
* JsonFormat.shape).
*
* #since 2.9
*/
protected final int _defaultNumericShape;
/**
* Marker set to non-0 if (and only if) property or type override exists.
*
* #since 2.9
*/
protected final int _shapeOverride;
I code for about 12 years, but I've never get used to TDD in all this time.
Well, things are about to change, but since I'm learning all by myself, I hope you guys could help me.
I'm posting a game example for a VERY SIMPLE chest class.
When the player grabs a chest, it registers the current time it was obtained.
This chest takes some time to open so, I need, for UI reasons, to show the remaining time it takes to open.
Each chest has a type, and this type is bound to a database value of how much time it would take to open.
This is a "no-testing-just-get-things-done-fast-mindset". Consider that ChestsDatabase and DateManager are singletons containing the database-bound values and the current system time wrapped into a class.
public class Chest {
private readonly int _type;
private readonly float _timeObtained;
public Chest(int type, float timeObtained) {
_type = type;
_timeObtained = timeObtained;
}
public bool IsOpened() {
return GetRemainingTime() <= 0;
}
// It depends heavily on this concrete Singleton class
public float GetRemainingTime() {
return ChestsDatabase.Instance.GetTimeToOpen(_type) - GetPassedTime();
}
// It depends heavily on this concrete Singleton class
private float GetPassedTime() {
return DateManager.Instance.GetCurrentTime() - _timeObtained;
}
}
Of course, I could have made it in a Dependency Injection fashion and get rid of the singletons:
public class Chest {
private readonly ChestsDatabase _chestsDatabase;
private readonly DateManager _dateManager;
private readonly int _type;
private readonly float _timeObtained;
public Chest(ChestsDatabase chestsDatabase, DateManager dateManager, int type, float timeObtained) {
_chestsDatabase = chestsDatabase;
_dateManager = dateManager;
_type = type;
_timeObtained = timeObtained;
}
public bool IsOpened() {
return GetRemainingTime() <= 0;
}
public float GetRemainingTime() {
return _chestsDatabase.GetTimeToOpen(_type) - GetPassedTime();
}
private float GetPassedTime() {
return _dateManager.GetCurrentTime() - _timeObtained;
}
}
What if I use interfaces to express the same logic? This is going to be much more "TDD-friendly", right? (supposing that I've done the tests first, of course)
public class Chest {
private readonly IChestsDatabase _chestsDatabase;
private readonly IDateManager _dateManager;
private readonly int _type;
private readonly float _timeObtained;
public Chest(IChestsDatabase chestsDatabase, IDateManager dateManager, int type, float timeObtained) {
_chestsDatabase = chestsDatabase;
_dateManager = dateManager;
_type = type;
_timeObtained = timeObtained;
}
public bool IsOpened() {
return GetRemainingTime() <= 0;
}
public float GetRemainingTime() {
return _chestsDatabase.GetTimeToOpen(_type) - GetPassedTime();
}
private float GetPassedTime() {
return _dateManager.GetCurrentTime() - _timeObtained;
}
}
But how the hell am I supposed to test something like that?
Would it be like this?
[Test]
public void SomeTimeHavePassedAndReturnsRightValue()
{
var mockDatabase = new MockChestDatabase();
mockDatabase.ForType(0, 5); // if Type is 0, then takes 5 seconds to open
var mockManager = new MockDateManager();
var chest = new Chest(mockDatabase, mockManager, 0, 6); // Got a type 0 chest at second 6
mockManager.SetCurrentTime(8); // Now it is second 8
Assert.AreEqual(3, chest.GetRemainingTime()); // Got the chest at second 6, now it is second 8, so it passed 2 seconds. We need 5 seconds to open this chest, so the remainingTime is 3
}
Is this logically right? Am I missing something? Because this seems so big, so convoluted, so... wrong. I had to create 2 extra classes ~just~ for the purpose of these tests.
Let's see with a mocking framework:
[Test]
public void SomeTimeHavePassedAndReturnsRightValue()
{
var mockDatabase = Substitute.For<IChestsDatabase>();
mockDatabase.GetTimeToOpen(0).Returns(5);
var mockManager = Substitute.For<IDateManager>();
var chest = new Chest(mockDatabase, mockManager, 0, 6);
mockManager.GetCurrentTime().Returns(8);
Assert.AreEqual(3, chest.GetRemainingTime());
}
I got rid of two classes with the framework, but still, I feel there's something wrong. Is there a simpler way in my logic? In this single case, would you use a mocking framework or implemented classes?
Would you guys get rid of the tests altogether or would you insist in any of my solutions? Or how to make this solution better?
Hope you can help me in my TDD journey. Thanks.
For your current design your last attempt is logically right and close to what I would consider an optimal test case.
I recommend extracting mock variables to field. I would also reorder test lines to have a clear distinction between setup, execution and verification. Extracting chest type to constant also makes the test easier to understand.
private IChestsDatabase mockDatabase = Substitute.For<IChestsDatabase>();
private IDateManager mockManager = Substitute.For<IDateManager>();
private const int DefaultChestType = 0;
[Test]
public void RemainingTimeIsTimeToOpenMinusTimeAlreadyPassed()
{
mockDatabase.GetTimeToOpen(DefaultChestType).Returns(5);
mockManager.GetCurrentTime().Returns(6+2);
var chest = new Chest(mockDatabase, mockManager, DefaultChestType, 6);
var remainingTime = chest.GetRemainingTime();
Assert.AreEqual(5-2, remainingTime);
}
Now for a more general comment. The main benefit of TDD is it gives you feedback on your design. Your feelings that the test code is big, convoluted and wrong are an important feedback. Think of it as a design pressure. Tests will improve both with test refactoring, as well as when the design improves.
For your code, I would consider these design questions:
Are responsibilities assigned properly? In particular, is it Chest's reponsibility to know the passed and remaining times?
Is there any concept missing in the design? Maybe each chest has a Lock, and there is a time-base Lock.
What if we passed the TimeToOpen instead of Type to Chest upon construction? Think of it as passing a needle instead of passing a haystack, in which the needle is yet to be found. For reference, see this post
For a good discussion of how tests can provide design feedback, refer to the Growing Object Oriented Software Guided by Tests by Steve Freeman and Nat Pryce.
For a good set of practices for writing readable tests in C# I recommend The Art of Unit Testing by Roy Osherove.
There are some major points that are needed to be considered while writing unit tests as shown
Separate project for unit testing.
One class for writing unit tests of functions in one class of main
code.
Covering conditions within functions.
Test Driven development (TDD)
If you really want to know more (with examples), have a look at this tutorial
Unit Tests c# - best practices https://www.youtube.com/watch?v=grf4L3AKSrs
Sometimes when you create a class you can add there several properties (new data members) that you are not certain if you want to do or not. For example, I have a casino slots game. I have tiles and tiles are spinning on different reels. So once 3 tiles come on the same line then player wins 3$, 4 tiles - 4$ and 5 tiles - 5$ for tile A and for tile B player wins 5$, 10$, 20$ accordingly. Should, for example, each tile store the data of its reward or there should be a reward manager for checking how many tiles are consecutive next to each other to give the reward to the player?
Please note that I don't want to have such a situation. But I find me many times thinking "Should I add this data, and consequently, corresponding logic the my class or not?". I worry about single responsibility principle when I want to have different managers for such things, but on the other hand I came to a situation to create several singletons or singleton-like classes.
Well, this sounds a lot like a use case for the Strategy Pattern.
As far as I am concerned (never been to a casino, since they're prohibited here in my country), most of slot machines work the same way.
So, you might think of one implementation as (pseudo-java code):
class Figure {
private String representation;
}
class Slot {
private Set<Figure> figures;
public Figure getRandom() {
// retrieve random figure from a slot
}
}
interface IRewardStrategy {
public int getReward(SlotMachine machine);
}
class OneFoldRewardStrategy implements IRewardStrategy {
public int getReward(SlotMachine machine) {
return machine.getCurrentLinedSlotsCount();
}
}
class TenFoldRewardStrategy implements IRewardStrategy {
public int getReward(SlotMachine machine) {
return 10 * machine.getCurrentLinedSlotsCount();
}
}
class SlotMachine {
private int slotCount;
private List<Slot> slots;
private List<Figure> currentRollResult;
private IRewardStrategy rs;
public SlotMachine(List<Slot> slots, IRewardStrategy rs) {
this.slots = slots;
this.rs = rs;
}
public void roll() {
// For each slot, get random figure
}
public int getTotalSlots() {
return slotCount;
}
public int getCurrentLinedSlotsCount() {
// Iterates over the current roll result and get the number of lined slots
}
public int getReward() {
this.rs.getReward(this); // delegates to the reward strategy
}
}
// Usage
SlotMachine machine = new SlotMachine(..., new TenFoldRewardStrategy());
machine.roll(); // suppose this give 3 slots in a row...
print(machine.getReward()); // This will yield 30
Attention: This is a very bare code, just to give you an idea, it has several problems.
I am the new to the programming and now I have a query regarding the variable and properties which is "what is the difference between declaring public variable and public properties?". Could anyone explain me with some instances?
Alot of people have different views on what is the "right" way, just different coding standards. Personally i think public properties give you a little more control as in you can have some simple logic in the get or set methods. Where as public properties are fine if you just want some quick global variable.
There are some instances in .net when you have to have properties rather than public variables e.g. usually when binding to datasources etc.
for more info check this link:
codinghorror.com
To clarify a little of what John said, properties allow you to add limitations and logic to what you are doing.
For instance if I have a rectangle class
class Rectangle
{
private float mWidth;
private float mHeight;
private float mArea;
public float width
{
get
{
return mWidth;
}
set
{
mWidth = value;
mArea = mHeight*mWidth;
}
}
public float height
{
get
{
return mHeight;
}
set
{
mHeight = value;
mArea = mHeight*mWidth;
}
}
public float area()
{
return mArea;
}
}
So rect.width += 20;
will update both the width and area;
Obviously this is a dumb example, but you could have done this without the properties for width and height, using public variables instead and instead just used
public float area
{
get
{
return width*height;
}
}
This will give you the correct area if you say float x = rect.area, but will not let you say something like rect.area = 40.
There are many more in depth things that you can do with properties, like databinding, for instance, but if you are just starting to program, you will get to this later.
For right now, you can treat a property as a convenient method that does not require () and that can take or give a variable.
If it is doing nothing but getting and setting, its probably better off as a variable.
If it is doing alot of internal work, and affect a considerable portion of your class, it should probably be a method.
If it is a quick function
to validate input (float rotation{set{mRotation = value%360;}})
or a multiple check output ( bool isInMotion{get{return (!isTurning && ! isMoving)}}
propertys work well.
No rules are final of course.
I hope this gives you a basic understanding of properties vs variables, though as always there is plenty more to learn.
Good Luck!