Design template for private members access?

Use this simple example:

Connect4Board.cs:

public class Connect4Board { private Box[,] _boxes = new Box[7, 6]; public void DropPieceAt(int column, bool redPiece) { //Safe modifications to box colors. } public Box GetBoxAt(int x, int y) { return _boxes[x, y]; } } 

Box.cs :

 public class Box { public bool IsRed { get; private set; } public bool IsEmpty { get; private set; } } 

I want GetBoxAt() return a field with read-only properties. However, I want my Connect4Board be able to change the colors of the boxes.

Suppose I don’t want to use the internal modifier at all.

My solution (pretty ugly):

 public class Connect4Board { private Box.MutableBox[,] _mutableBoxes = new Box.MutableBox[7, 6]; public Connect4Board() { for (int y = 0; y < 6; y++) { for (int x = 0; x < 7; x++) { _mutableBoxes[x, y] = new Box.MutableBox(); } } } public void DropPieceAt(int column, bool isRed) { //Safe modifications to box colors. } public Box GetBoxAt(int x, int y) { return _mutableBoxes[x, y].Box; } } public class Box { public bool IsRed { get; private set; } public bool IsEmpty { get; private set; } private Box() { } public class MutableBox { public Box Box { get; private set; } public MutableBox() { Box = new Box(); } public void MakeRed() { //I can modify Box here } public void MakeYellow() { //I can modify Box here } public void MakeEmpty() { //I can modify Box here } } } 

Is there any good design to make it more elegant?

+4
source share
4 answers

Solution 1

You can create a wrapper around the Box that is immutable. Connect4Board will use the MutableBox class internally, but will display the ImmutableBox consumers.

 public interface IBox { bool IsRed { get; } bool IsEmpty { get; } } public class MutableBox : IBox { public bool IsRed { get; set; } public bool IsEmpty {get; set; } public IBox MakeImmutable() { return new ImmutableBox(this); } } public class ImmutableBox : IBox { private IBox innerBox; public ImmutableBox(IBox innerBox) { this.innerBox = innerBox; } public bool IsRed { get { return innerBox.IsRed; } } public bool IsEmpty { get { return innerBox.IsEmpty; } } } public class Connect4Board { private MutableBox[,] boxes = new MutableBox[7, 6]; public void DropPieceAt(int column, bool redPiece) { // perform modifications } public IBox GetBoxAt(int x, int y) { return boxes[x,y].MakeImmutable(); } } 

Decision 2

Could you use an explicit interface implementation to achieve this? Create an IMutableBox interface.

 public interface IMutableBox { void SetIsRed(bool isRed); void SetIsEmpty(bool isEmpty); } public class Box : IMutableBox { private bool isRed; private bool isEmpty; public bool IsRed { get { return isRed; } } public bool IsEmpty { get { return isEmpty; } } void IMutableBox.SetIsRed(bool isRed) { this.isRed = isRed; } void IMutableBox.SetIsEmpty(bool isEmpty) { this.isEmpty = isEmpty; } } 

Now, to mutate Box , you need to drop it on an IMutableBox .

 var box = new Box(); var mutableBox = box as IMutableBox; mutableBox.SetEmpty(true); 
+1
source

There are several strategies you could use.

It is often useful to program interfaces. The IBox interface below will not allow people to edit the window (without dropping it on the Box ), but it still leaves your code simple.

 public class Connect4Board { private Box[,] _boxes = new Box[7, 6]; public void DropPieceAt(int column, bool redPiece) { //Safe modifications to box colors. } public IBox GetBoxAt(int x, int y) { return _boxes[x, y]; } } public interface IBox { bool IsRed { get; } bool IsEmpty { get; } } public class Box : IBox { public bool IsRed { get; set; } public bool IsEmpty { get; set; } } 

Another approach would be to make fields immutable (e.g. strings), and instead of changing the state of your fields, you simply change which field is at your location in your array:

 public class Connect4Board { private Box[,] _boxes = new Box[7, 6]; public Connect4Board() { for(int i = 0; i<7; i++) { for(int j = 0; j<6; j++) { // Notice how you're not changing a color, but assigning the location _boxes[i,j] = Box.Empty; } } } public void DropPieceAt(int column, bool redPiece) { // Modifications to the top empty location in the given column. } public Box GetBoxAt(int x, int y) { return _boxes[x, y]; } } public class Box { public bool IsRed { get; private set; } public bool IsBlack { get; private set; } public bool IsEmpty { get; private set; } private Box() {} public static readonly Box Red = new Box{IsRed = true}; public static readonly Box Black = new Box{IsBlack = true}; public static readonly Box Empty = new Box{IsEmpty = true}; } 
+4
source

Did this work for you? Make Box Immutable with a static factory and add static properties that return new fields with different colors

  public class Box { private Box() {} private Box(Color color) { Color = color; } public static Box Make(Color color) { return new Box(color); } public static Box RedBox { get { return new Box(Color.Red); } } public static Box GreenBox { get { return new Box(Color.Green); } } public static Box BlueBox { get { return new Box(Color.Blue); } } // ... etc. } 
+3
source

You can make ReadOnlyBox , which can be a facade for your Box , like a ReadOnlyCollection .

 [Flags] public enum BoxState { Empty = 0, Red = 1 << 0, Black = 1 << 1 } [Flags] public enum BoardColor { Red = 1 << 0, Black = 1 << 1 } public interface IBox { BoxState State { get; } } public class Box : IBox { public BoxState State { get; set; } } public class ReadOnlyBox : IBox { private readonly IBox _box; public ReadOnlyBox(IBox box) { _box = box; } public BoxState State { get { return _box.State; } } } public class Connect4Board { private const int _boardWidth = 7; private const int _boardHeight = 6; private Box[,] _boxes = new Box[_boardWidth, _boardHeight]; public void DropPieceAt(int column, BoardColor color) { for(int height = 0; height < _boardHeight; height++) { if(_boxes[column, height].State != BoxState.Empty) continue; _boxes[column, height].State = (BoxState)color; break; } } public IBox GetBoxAt(int x, int y) { return new ReadOnlyBox(_boxes[x, y]); } } 
+1
source

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


All Articles