Best way to use a base class, is this right? - c#

I am coding an application that I thought would be a good chance to use a base class. I have Player class which holds an instance for each player on my game, I also have a PlayerManager class that has a dictionary of all the connected players, although I'll leave the PlayerManager class out of this question as this is just about the Player and PlayerData class.
So, I thought instead of having something like this, please note before checking this code snippet that I have removed a lot of the code and just shown a minimal example.
class Player
{
public PlayerData;
}
class PlayerData
{
public string Username;
public string Motto;
public string NickName;
}
class SomeOtherClass
{
public void Test()
{
var player = GetPlayer();
Console.WriteLine("Hello, I am " + player.PlayerData.Username);
}
}
I thought why have a method when I can have a base class? So I thought great, lets use a base class, this is what I ended up with.
internal class Player : PlayerData, IDisposable
{
private readonly Socket _socket;
private bool _disposeCalled;
private bool _receivingData;
private bool _hasAuthenticated;
public Player(Socket socket)
{
_socket = socket;
}
public void OnAuthenticated(MySqlDataReader reader)
{
if (_hasAuthenticated)
{
return;
}
_hasAuthenticated = true;
AssignData(reader);
}
public void Dispose()
{
if (_disposeCalled)
{
return;
}
_disposeCalled = true;
if (_receivingData)
{
_receivingData = false;
try
{
if (_socket != null && _socket.Connected)
{
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
}
}
catch
{
// ignored
}
_socket?.Dispose();
}
if (_hasAuthenticated)
{
SaveData();
}
}
}
internal class PlayerData
{
public int Id;
public string Username;
public void AssignData(MySqlDataReader reader)
{
while (reader.Read())
{
Id = reader.GetInt32("id");
Username = reader.GetString("username");
}
}
public void SaveData()
{
using (var dbConnection = Program.Server.Database.Connection)
{
dbConnection.SetQuery("UPDATE `users` SET `username` = #username WHERE `id` = #id");
dbConnection.AppendParameter("id", Id);
dbConnection.AppendParameter("username", Username);
dbConnection.ExecuteNonQuery();
}
}
}
You'll probably see the base class has a constructor, that's because I was going to just pass the PlayerData's data with the Player's constructor, but I wont actually get the data untill the Player's class has been fully initialized, I don't know when that will be as its done via socket packets, I just assign the data when I notice its been authenticated.
The point of my question is, should I use a base class like this, or should I not use a base class due to the fact I'm not initializing the data via the constructor, or is it okay to assign it via another method later on? Do I really need a base class, am I not following the right official rules for what a base class is and used for? Basically I just want to know, with this call stack should I be using a base class or method? I'm unsure on the rules.

So, the rules are not rules so much as guidelines (that not everyone really agrees on).
THAT SAID, I don't really see any benefit of lumping these classes together, although that could be because of so much of the code being removed.
In general, a good rule of thumb is not to use inheritance unless you have a good reason--a significant amount of code reuse that couldn't be achieved through composition, for example. In most cases, your code will be easier to maintain if you design with an eye for reducing dependencies (coupling), and the dependency between a subclass and its superclass is very strong. This means keeping things separate.
One technique you could do to simplify calls to player data is to "promote the interface"--basically, add the methods/properties you want as a sort of facade on the Player class, and have that relay the code to its PlayerData object. This has a few benefits:
1. It hides dependencies on PlayerData, which means you are free to change implementation to consolidate or use a different type (for example, if you just wanted to put those values in a data structure in the Player class)
2. It allows you to handle the case where PlayerData is being requested, but hasn't been initialized yet. For example, you could return default values or throw a custom exception.
3. Player and PlayerData are free to vary independently. So, if you run across a valid reason to subclass one or both of them, you won't be constrained.
In summary, it doesn't look like you really gain much from using inheritance in this way, but it would cut off design choices down the road. Also, anytime you are using inheritance to describe a relationship that is not an "IS A" relationship (PlayerData Is A Player? nope)--that smells fishy.
Again, guidelines. Bottom line is you want to design a system that you want to maintain, and design decisions come with trade-offs (often between simplicity and flexibility). So, if you decide there is a good reason to keep this as a subclass, just document it and don't worry about the OO Police coming after you for breaking the rules ;)

Related

Is it fine to typecast from one implementation type to another while using an object?

I've a simple code base with few 'weapon' concrete classes which implements different contracts in order to be used by its clients.
My contracts:
public interface IWeaponPrimaryAttack
{
void DoAttack();
}
public interface IWeaponSecondaryAttack
{
void DoSecondaryAttack();
}
public interface IReloadable
{
void Reload();
}
Concrete implementation or the actual weapons:
public class Katana : IWeaponPrimaryAttack, IWeaponSecondaryAttack
{
public void DoAttack(){Console.WriteLine ("Swing");}
public void DoSecondaryAttack() {Console.WriteLine ("Stab");}
}
public class ShotGun : IWeaponPrimaryAttack, IReloadable
{
public void DoAttack(){Console.WriteLine ("Swing");}
public void Reload() {//reload it}
}
Clients that uses these concrete classes:
public class PrimaryAttack
{
private IWeaponPrimaryAttack _attack;
public PrimaryAttack(IWeaponPrimaryAttack attack)
{
_attack = attack;
}
public void DoAttack()
{
_attack.DoAttack();
}
}
public class SecondaryAttack
{
private IWeaponSecondaryAttack _attack;
public SecondaryAttack(IWeaponSecondaryAttack attack)
{
_attack = attack;
}
public void DoSecondaryAttack()
{
_attack.DoSecondaryAttack();
}
}
public class WeaponReload
{
private IReloadable _reloader;
public WeaponReload(IReloadable reloader)
{
_reloader = reloader;
}
public void Reload()
{
_reloader.Reload();
}
}
New of course the instantiation of concrete class only be known when the user selects one among many weapons(one among ShotGun, Katana, etc).
Let say the use has selected ShotGun as the weapon, based on the selection it might go like this:
IWeaponPrimaryAttack weapon = new ShotGun(); // get it from a factory
PrimaryAttack primaryAttack = new PrimaryAttack(weapon);
primaryAttack.DoAttack();
Now for the WeaponReload have to do a typecast here in order to use it.
WeaponReload reloader = new WeaponReload ((IReloadable)weapon);
reloader.Reload();
I have questions around it,
Should I really have to end up typecasting eventually?
Or there is a better way to handle this object creation part.
Or there is entirely a better design that I can come up with which
does not necessarily ends up in casting.
Or casting it like this is totally fine.
Not so sure why you need all these extra delegating wrappers? Anyhow, there's a few things at play here.
Maximizing composition
You've used a concrete type per weapon type here, but you could also put more emphasis on composition and have a single all-encompassing Weapon class that delegates all it's inner workings to strategies.
e.g.
Rather than Weapon shotgun = new Shotgun(); you could have Weapon shotgun = Weapons.shotgun() where the factory method may look like:
return new Weapon.Builder()
.withPrimaryAttack(...)
.withoutSecondaryAttack()
.withSlowReload().build();
Maximizing composition makes the design very flexible and could allow you to introduce new weapon types dynamically if needed or even change certain aspects of a weapon at runtime (e.g. shotgun now fires knifes b/c of a picked-up powerup).
Following the ISP
In the composition-based approach described above, you may notice that the Weapon's interface will become bloated with all sort of things weapons can do. Clients depending on the Weapon class will indirectly depend on all the various implicit interface methods they may never call.
In order to reduce clients coupling you could very well make sure that Weapon features are segregated into many interfaces such as IReloadable, etc. The Weapon class would implement them all, but client code interested in only a subset of weapon features could still depend on these interfaces rather than Weapon.
e.g.
reload(weapon);
void reload(IReloadable reloadable) {
if (stamina < ...) throw ...;
reloadable.reload();
}
ISP & feature-detection
Considering your original design, I don't think there's anything fundamentally wrong with using instanceof as a feature detection mechanism.
Using instanceof to match concrete types is certainly wrong, but matching interfaces is most likely fine.
weapon instanceof Shotgun //bad
weapon instanceof IReloadable //ok
Note that you should always check with instanceof before casting. Also note that you need to think of an approach to make weapon implementers know the set of potential weapon-feature interfaces they could implement.

Can I prevent a private variable from being changed by other objects of the same class?

I'm multithreading a real-time game, and would like to prevent the state variables of objects on one thread from being set from another thread. This will make preventing race conditions a lot easier.
I would still like to be able to read the state of other objects, however. I'm intending to use a double buffer system, where one state object is used as the forebuffer and makes state changes while the other is used as the backbuffer and provides the (previous frame's) state to other objects. I need to be able to read state information from the backbuffer to make changes in the forebuffer.
The issue is that even if the variables setter is private, it's possible to change it from another object of the same class.
public class State
{
//Some example state information
public string StateVar1 { get; private set; }
//This method will be farmed out to multiple other threads
public void Update(State aDifferentStateObject)
{
StateVar1 = "I want to be able to do this";
string infoFromAnotherObject = aDifferentStateObject.StateVar1; //I also want to be able to do this
aDifferentStateObject.StateVar1 = "I don't want to be able to do this, but I can";
}
}
May not be the most direct solution, but one way to protect the properties is to use an interface.
public interface IState
{
string StateVar1 { get; }
}
public class State:IState
{
//Some example state information
public string StateVar1 { get; private set; }
//This method will be farmed out to multiple other threads
public void Update(IState aDifferentStateObject)
{
StateVar1 = "I want to be able to do this"; // Allowed
string infoFromAnotherObject = aDifferentStateObject.StateVar1;
aDifferentStateObject.StateVar1 = "I don't want to be able to do this, but I can"; // NOT allowed
}
}
If you're writing a class, it's assumed that you'll make the class work the way you want it to work. The purpose of making stuff private is to prevent your co-workers (or clients) from breaking your class's concerns while they work on their own classes/functions/modules.
Saying "I don't want to be able to do this thing." is somewhat missing the point.
That said, the thing that's nice about less permissive languages in general is that they prevent your co-workers from writing crappy or non-idiomatic code. The other answers show idioms you could use that would make it harder for your peers to later edit break your nice elegant pattern. Anu Viswan's get's my vote.
add field this0=this and in the setter, check that this==this0.
it's possible to change it from another object of the same class.
You cannot stop your own class from setting private setters.
I mean after all, you are the author of that class, its only your fingers you have to worry about.
public class SomeOtherNonRelatedClass
{
public void Update(State aDifferentStateObject)
{
// the world is as it should be
aDifferentStateObject.StateVar1 = "bang!!!" // compiler error
}
}
If you would like to prevent your self from changing your own member, then use an extension method
public class Extensions
{
public void Update(this State aDifferentStateObject)
{
// the world is as it should be
aDifferentStateObject.StateVar1 = "bang!!!" // compiler error
}
}
or make it truly read only (though is probably not useful)
public string StateVar1 { get; }
or a backing field, so you can set it internally
private string backingField;
public string StateVar1
{
get => backingField;
}

First experience of using interfaces in C#?

I have an interface:
interface ISqlite
{
void insert();
void update();
void delete();
void select();
}
And custom service class:
class SqliteService
{
public SQLiteDatabase driver;
public SqliteService() {
SqliteConnection(new SQLiteDatabase());
}
public void SqliteConnection(SQLiteDatabase driver)
{
this.driver = driver;
}
public void select(ISqlite select) {
select.select();
}
public void insert(ISqlite insert) {
insert.insert();
}
public void delete(ISqlite delete)
{
delete.delete();
}
}
And last class Pacients that realizes ISqlite interface:
class Pacients: ISqlite
{
public List<ClientJson> pacients;
public Pacients() {
this.pacients = new List<ClientJson>();
}
public void add(ClientJson data) {
this.pacients.Add(data);
}
public void insert()
{
throw new NotImplementedException();
}
/* Others methos from interface */
}
I try to use my code like as:
/* Create instance of service class */
SqliteService serviceSqlite = new SqliteService();
/* Create instance of class */
Pacients pacient = new Pacients();
pacient.add(client);
serviceSqlite.insert(pacient);
As you can see above I send object pacient that realizes interface ISqlite to service. It means that will be called method insert from object pacient.
Problem is that I dont understand how to add data in this method using external class: SQLiteDatabase()? How to get access to this.driver in service class from object pacient?
Edit 1
I think I must move instance of connection new SQLiteDatabase() to db inside Pacients class is not it?
Generally speaking, I would favor a solution where the data objects themselves don't know anything about how they're stored, i.e. they have no knowledge of the class that communicates with the database. Many ORMs do just that.
Of course it might not be easy depending on the specifics of your situation... Try to examine what your methods on each object actually need; generally speaking they need the values of properties, and what column each property corresponds to, right? So any external class can do this if it knows these bits of information. You can specify the name of the column with a custom attribute on each property (and if the attribute isn't there, the column must have the same name as the property).
And again, this is the most basic thing that ORMs (Object Relational Mappers) do, and in addition they also manage more complicated things like relationships between objects/tables. I'm sure there are many ORMs that work with SqlLite. If you're OK with taking the time to learn the specifics of an ORM, that's what I would recommend using - although they're not silver bullets and will never satisfy all possible requirements, they are in my opinion perfect for automating the most common day to day things.
More to the point of the question, you can of course make it work like that if you pass the SQLiteDatabase object to the methods, or keep it in a private field and require it in the constructor or otherwise make sure that it's available when you need it; there's no other simple solution I can think of. And like you pointed out, it implies a certain degree of coupling.
You can change the signature of interface's methods to pass an SQLiteDatabase object.
interface ISqlite
{
void insert(SQLiteDatabase driver);
void update(SQLiteDatabase driver);
void delete(SQLiteDatabase driver);
void select(SQLiteDatabase driver);
}
Example call from the service:
public void insert(ISqlite insert)
{
insert.insert(driver);
}
I think you can figure out the rest by yourself.

C#/AS3 How do I create a public global data object that any other object can read, but only certain objects can set?

Here is the conundrum. I have a specific set of state variables that are used in almost every supporting object I have, and I want those variables to be able to be read by any object that needs to read them, but I want to protect them so that only 1 object has the ability to set them.
For example, lets say I am making a poker game. Variables like:
- Minimum Ante
- Maximum Bet
- Maximum Number of Players
- Current GameState (Placing Bets, Shuffling, Dealing, Paying, etc.)
Personally, I prefer small compact component classes, so lets say I have the majority of the poker game logic in 1 controller class, but i have 50 supporting objects that handle everything that isn't the poker game logic itself, such as a PlayerInterface, a graphics controller, 'The Deck' to handle shuffle and deal logic, etc. Alot of my smaller support classes need to see what the minimum ante is, and the current method I am using is for the controller class to pass these variables into the supporting classes as parameters.
The obvious downside to this is I have 50 supporting objects all holding on to their own local variables for minimum ante to hold the same information that I am passing to them from the controller. Wasted parameters, memory, and opens a ton of risk if any of those variables ever get out of sync.
So, how to I make these variables global so everyone can access and read them? The knee jerk reactionary answer is some public static variables, however this presents the problem that anyone could also write to them. Not only do I not want my supporting objects having the power to change the minimum ante without the controller's knowledge, but I also don't want the client shell that holds the poker game to be able to change them without first going through the proper checks contained in the controller.
So what do I do? Someone once mentioned to me the idea of a Singleton, but after plenty of research, most of it a few years old or more, I found about a 50/50 split in the community who say Singletons are a good idea vs those who think they aren't.
If not singletons or statics, then what? I am open to any ideas to research and try out.
Remember, I want any object, anytime, anywhere to be able to GET the data it needs, but only a very specific object to have the ability to SET the data, should it need to change, so that it can filter through the proper checks. By proper checks, I mean for example in the poker game, if a player has the ability to change the Minimum Bet on the table, he should only be able to do so between hands, or before a tournament begins. I don't want him messing with these things during play.
Thanks in advance for any input.
You could use interfaces approach here.
Declare two interfaces as
public interface IReadOnlyAccess
{
int Property{get;}
}
public interface IFullAccess
{
int Property{get;set;}
}
Then your class would implement both interfaces like
public interface MyClass: IReadOnlyAccess, IFullAccess
{
public int Property{get;set;}
}
Then wherever you need full access you get it via IFullAccess, if otherwise - via IReadOnlyAccess.
Make an inner class, it will have access to the main classes private vars:
public class OuterClass
{
public string StringProperty { get; private set; }
public InnerClass CreateInnerClass()
{
InnerClass ic = new InnerClass(this);
return ic;
}
public class InnerClass
{
private OuterClass _outer;
public InnerClass(OuterClass oc)
{
_outer = oc;
}
public string Prop
{
get
{
return _outer.StringProperty ;
}
set
{
_outer.StringProperty = value;
}
}
}
}
So create the main class that most people have readonly access:
var oc = new OuterClass();
oc.StringProperty = "123"; <-- not allowed, is `readonly`
To write to properties, create inner class instance:
var oc = new OuterClass();
var ic = oc.CreateInnerClass();
ic.StringProperty = "123";
Seems like the cleanest, easiest solution is to have everything done in your controller class.
Let's say something like this:
AS3:
//adding the final keyword, locks this class so others can't extent/inherit from it
public final class MyController {
//create a privately scoped var (it can only be accessed in this class)
private var minBet:Number = 0;
//create a public getter that can be read by any class/object
public function get minimumBet():Number {
return minBet;
}
private function set minimumBet(value:Number):void {
//do you checks etc
minBet = value;
}
}
C#
//sealed in C# is the same as final in AS3
public sealed class MyController
{
private float minBet = 0;
public float minimumBet
{
get { return minBet; }
}
}
instanceOfMyController.minBet //will throw an error
instanceOfMyController.minimumBet = 10; //will throw an error
instanceOfMyController.minimumBet //will supply the value of the minBet var
If you're doing a lot cross-language code, consider checking out something like Haxe which can compile out to AS3 or C# with the same code.

Using constructors of monobehaviors

OK, I know why we don't use constructors on monobehaviors in Unity. For nearly all of the use cases, Start and Awake fit perfectly. Usually.
However, there's a great C# feature that only can be used with constructors — readonly fields. In my particular situation, I work on a project with a lot of developers and write an abstract MonoBehavior that will be subclassed and rewritten a lot of times by a lot of different people. And I want a field to act like constant throughout object's lifetime (or it WILL introduce strange, hard-detectable bugs) but with different values in different subclasses — in other words, a classic use-case for a readonly field. (I don't want to use properties because they have no language-enforce obligation of staying the same.)
So — can I safely use MonoBehavior's constructors? Won't some strange dragon come out of the lair somewhere down the road? What should I know if I choose to use them?
I think the main reasons Unity wants you to stay away from using the constructor is that the constructor isn't called on the main thread, and the constructor is called before serialized data is restored to the object.
So if the readonly fields you're setting in the constructor depend on data from serialized fields, then they won't work right. And if they don't then you can just assign them at initialization.
You could also use a container object to keep your readonly values, but there's nothing stopping someone else from re-assigning that container later.
using UnityEngine;
using System.Collections;
public class ReadOnlyTest : MonoBehaviour {
public string part1 = "alpha"; // change these values in the editor and
public string part2 = "beta"; // see the output of the readonly variable "combined"
public readonly string combined;
// just assign to readonly vars.
public readonly string guid = System.Guid.NewGuid().ToString();
public readonly float readOnlyFloat = 2.0f;
public class ReadOnlyContainer {
public readonly int readOnlyInt;
public readonly float readOnlyFloat;
public readonly string readOnlyString;
public ReadOnlyContainer(int _int, float _flt, string _str) {
readOnlyInt = _int;
readOnlyFloat = _flt;
readOnlyString = _str;
}
public override string ToString() {
return string.Format("int:{0} float:{1} string:{2}", readOnlyInt, readOnlyFloat, readOnlyString);
}
}
public ReadOnlyTest() {
combined = part1 + part2;
}
public ReadOnlyContainer container;
void Awake() {
if (container == null) {
container = new ReadOnlyContainer(Random.Range(-100,100), Time.realtimeSinceStartup, System.Guid.NewGuid().ToString());
}
}
void Start () {
Debug.Log(container.ToString());
Debug.Log("combine1: " + combined);
Debug.Log("guid: " + guid);
}
}
Many unity classes are created by reflection, and there's no way for unity to non-default constructors properly; hence the limitation.
#Calvin's answer points out one very good option: create classes that are not derived from MonoBehaviour; these can have constructors like any other C#. You can put those classes into fields in MonoBehaviours as long as your code can tolerate missing instances. If you use the typical quasi-singleton pattern from #Calvin's answer you'll always get an instance when you need one, and you can push the 'give me an instance the first time' logic into a method that can be overridden in derived classes to customize behavior.
If you want constant-like behavior, with the option of different values in derived classes it may be easier to define a method rather than a field. The method is effectively read-only, and it has more predictable mutations as per #Jerdak's answer.
If you must have constructors, the last option is to use the monobehavior as a minimal placeholder and write all of the interesting stuff in a class of your own, then delegate all of the work in the Monobehavior to your class.
using UnityEngine;
using System.Collections;
public class OuterPlaceholder: MonoBehaviour {
public InnerBehavior _Inner;
public void Awake() {
if (_Inner == null) {
_Inner= new InnerBehavior(4);
}
}
public void Update()
{
_Inner.DoUpdate(this);
}
}
public class InnerBehavior
{
public readonly int UpConstant;
public InnerBehavior (int up)
{
UpConstant = up;
}
public void DoUpdate(MonoBehaviour owner)
{
owner.transform.Translate(Vector3.up * UpConstant * Time.deltaTime);
}
}
This option may work best if you are sure you're going to get a lot of complex inheritance as the project evolves.
Finally: It's perfectly OK to name the field _ReadOnlyField or _DoNotWrite or whatever to tell users not to muck with it. All Python programmers live with the possibility of somebody doing far worse things and it seems to work out fine most of the time :)
From the script refs:
If you attempt to define a constructor for a script component, it will
interfere with the normal operation of Unity and can cause major
problems with the project.
MonoBehaviours are constructed many times during serialization, something Unity does quite frequently in the editor and I suspect there is a lot more going on the hood to hook the C layer to C#. Ultimately the behavior is undefined so it's best not to try.
Regarding "but with different values in different subclasses", from MSDN:
assignments to the fields introduced by the declaration [readonly] can only occur as part of the declaration or in a constructor in the same class.
So no modification in derived classes.

Categories